树状数组整理(2.区间修改、二维)
1.区间整体加一个数,单点求: 已经很常用的方法了,就当成有多少线段覆盖,对a[l,r]k的操作转化为对辅助数组b[l]k,b[r1]-k,树状数组维护b[i]前缀和就好…… 具体来说,是对a[i]差分后生成新数组b[i],使得b[i]=a[i]-a[i-1],这样成段修改时: 对il或ir1,a
1.区间整体加一个数,单点求值:
已经很常用的方法了,就当成有多少线段覆盖,对a[l,r]+k的操作转化为对辅助数组b[l]+k,b[r+1]-k,树状数组维护b[i]前缀和就好……
具体来说,是对a[i]差分后生成新数组b[i],使得b[i]=a[i]-a[i-1],这样成段修改时:
对i
同时对b[i]求前缀和会发现:
sum(p)=b[1]+b[2]+...+b[p]=(a[1]-a[0])+(a[2]-a[1])+...+(b[p]-b[p-1])=a[p]-a[0]=a[p]
这样单点求值的方式也出来了,上代码(套用了下原始的BIT):
struct BIT_ex { BIT t; void init(int s) {t.init(s);} void change(int l, int r, _int k) {t.change(l,k); t.change(r+1,-k);} _int get(int p) {return t.sum(p);} };
2.区间整体加一个数,求区间和(前缀和):
好像不是很常见,普及推广一下……
区间整体的修改已经搞出来,肯定是要继续用结论了……
上面差分数组得出了sum(p)=a[p],这里求前缀和当然是求a[0]+a[1]+...+a[p]了~剩下的全是算数
a[0]+a[1]+a[2]+a[3]+...+a[p]=0+sum(1)+sum(2)+sum(3)+...+a[p]=(b[1])+(b[1]+b[2])+(b[1]+b[2]+b[3])+...+(b[1]+...+b[p])
b[1]在sum(1..p)中都出现,共p次,b[2]在sum(2..p)出现(p-1)次,类推可得
原式=p*b[1]+(p-1)*b[2]+(p-2)*b[3]+...+1*b[p]
本来想把每一项当成一个整体用BIT搞,但发现对于不同的p值,每项也会跟着变,显然没办法……
这里看到前面系数和b[]的下标和都是(p+1),考虑逆用倒序相加大法:
原式=(p+1)*(b[1]+b[2]+b[3]+...+b[p])-(1*b[1]+2*b[2]+3*b[3]+...+p*b[p])
前面括号里是直接对b[i]求的前缀和,后面括号是对i*b[i]求前缀和——系数和下标一致的项出来了!
好,这样我们可以搞两个BIT,一个是维护b[i]的前缀和,一个维护i*b[i]的前缀和,维护方法同上
为了减少依赖所以这里仍然套了原始BIT,套BIT_ex会更好写,上代码:
struct BIT_im { BIT t1; BIT t2; void init(int s) {t1.init(s); t2.init(s);} void chage(_int l, _int r, _int k) { t1.change(l,k); t1.change(r+1,-k); t2.change(l,l*k); t2.change(r+1,-(r+1)*k); } _int sum(_int p) {return (p+1)*t1.sum(p)-t2.sum(p);} };
3.二维(多维)树状数组:
一维是前缀和,sum(p)=sum{a[i],i
二维的话,sum(x,y)=sum{a[i][j],i
多维类似,只讨论二维
静态维护很简单:
for (int i=1; i <p><span>这样如果求(x1,y1)-(x2,y2)构成的矩形和,ans=s[x2][y2]-s[x1-1][y2]-s[x2,y1-1]+s[x1-1][y1-1]<br> 那么动态维护呢?首先对(a[i])[]这个数组可以用BIT来维护一个前缀和,再维护维护(a[i])[]前缀和BIT的前缀和……好绕<br> 总之呢,可以先用一组BIT可以维护多条平行线上的和,再用一个和它们正交的BIT把它们挂进去维护,此时原来那组BIT的意义其实已经变了……<br> 这个思路比较像下面这段代码(鸣谢mlzmlz95):</span></p> <pre class="brush:php;toolbar:false">for(i=1;i <p><span>那么上代码:</span></p> <pre class="brush:php;toolbar:false">struct BIT_2D { BIT c[N]; int n; void init(int s1,int s2) {n=s1; while (s1) c[s1--].init(s2);} void change(int x,int y,int k) {for (; x <p><span>这个实现中,我们通过外层BIT来确定里层BIT的更新,初始化要把它们循环一遍设定好尺寸<br> 至于3D,那就再挂个2D吧,不过求一个长方体和的公式有点复杂>_ 那么想搞多维难道就要把前面所有维的写出来吗……太麻烦了,我们直接手工inline一下,再稍作修改:</span></p> <pre class="brush:php;toolbar:false">struct BIT_2D_in { int c[N][M],n,m; void init(int s1,int s2) {n=s1; m=s2; memset(c,0,sizeof(c));} void change(int xx,int yy,int k) { for (int x=xx; x <p><span>这个实现中,我们可以看出来这两重循环直接控制好了下标,那么多维直接加几重循环就完事了,xx,yy当参数名可以在后面循环写x,y,我懒……</span></p> <p><br> <span>没了……其实全文可能没啥新鲜的<br> 下期预告:邪道(写萎)的BIT<br> </span></p>

ホットAIツール

Undresser.AI Undress
リアルなヌード写真を作成する AI 搭載アプリ

AI Clothes Remover
写真から衣服を削除するオンライン AI ツール。

Undress AI Tool
脱衣画像を無料で

Clothoff.io
AI衣類リムーバー

AI Hentai Generator
AIヘンタイを無料で生成します。

人気の記事

ホットツール

メモ帳++7.3.1
使いやすく無料のコードエディター

SublimeText3 中国語版
中国語版、とても使いやすい

ゼンドスタジオ 13.0.1
強力な PHP 統合開発環境

ドリームウィーバー CS6
ビジュアル Web 開発ツール

SublimeText3 Mac版
神レベルのコード編集ソフト(SublimeText3)

ホットトピック









1. まずDingTalkを開きます。 2. グループ チャットを開き、右上隅にある 3 つの点をクリックします。 3. このグループで私のニックネームを見つけます。 4. クリックして入力し、変更して保存します。

foreach ループを使用して PHP 配列から重複要素を削除する方法は次のとおりです。配列を走査し、要素がすでに存在し、現在の位置が最初に出現しない場合は、要素を削除します。たとえば、データベース クエリの結果に重複レコードがある場合、このメソッドを使用してそれらを削除し、重複レコードのない結果を取得できます。

Xianyuプラットフォームで製品を公開する際、ユーザーは実際の状況に応じて製品の地理的位置情報をカスタマイズできるため、潜在的な購入者は製品の特定の位置をより正確に把握できます。製品が無事に店頭に並べられれば、販売者の所在地が変わっても心配する必要はありません。 Xianyu プラットフォームは、柔軟で便利な変更機能を提供しています。公開された製品のアドレスを変更したい場合、どのように変更すればよいでしょうか? このチュートリアル ガイドでは、詳細なステップバイステップ ガイドが提供されます。助けてください、皆さん! Xianyu でリリース製品アドレスを変更するにはどうすればよいですか? 1. Xianyu を開き、公開したものをクリックして製品を選択し、[編集] をクリックします。 2. 位置決めアイコンをクリックし、設定したいアドレスを選択します。

PHP で配列をディープ コピーする方法には、json_decode と json_encode を使用した JSON エンコードとデコードが含まれます。 array_map と clone を使用して、キーと値のディープ コピーを作成します。シリアル化と逆シリアル化には、serialize と unserialize を使用します。

PHP の配列キー値の反転メソッドのパフォーマンスを比較すると、array_flip() 関数は、大規模な配列 (100 万要素以上) では for ループよりもパフォーマンスが良く、所要時間が短いことがわかります。キー値を手動で反転する for ループ方式は、比較的長い時間がかかります。

PHP で配列のディープ コピーを実行するためのベスト プラクティスは、 json_decode(json_encode($arr)) を使用して配列を JSON 文字列に変換し、それから配列に戻すことです。 unserialize(serialize($arr)) を使用して配列を文字列にシリアル化し、それを新しい配列に逆シリアル化します。 RecursiveIteratorIterator を使用して、多次元配列を再帰的に走査します。

多次元配列のソートは、単一列のソートとネストされたソートに分類できます。単一列のソートでは、array_multisort() 関数を使用して列ごとにソートできますが、ネストされたソートでは、配列を走査してソートするための再帰関数が必要です。具体的な例としては、製品名による並べ替えや、売上数量や価格による化合物の並べ替えなどがあります。

PHP の array_group_by 関数は、キーまたはクロージャ関数に基づいて配列内の要素をグループ化し、キーがグループ名、値がグループに属する要素の配列である連想配列を返すことができます。
