我是看這個學會的:mlystdcall
咕咕咕了好久的一個東西。
使用該算法的兩個條件:
- 題目允許使用離線算法;
- 答案無後效性,即修改區間中位置上5的值,不會對區間[1,4]的查詢產生影響。
定義表示對於若第項操作是查詢,則計算第中的所有修改操作對它造成的影響。
計算方法:
- ,遞歸計算
- 遞歸計算
- 計算中所有的修改對中的所有查詢造成的影響。
爲什麼這樣做是對的?
對於中的所有修改對查詢造成的影響已經在遞歸處理中計算完畢了,中的也已經遞歸計算完畢了,那麼只剩下中的修改對於中的查詢造成的影響了,故最後處理這一部分的影響。
從一道例題出發吧:
支持單點修改,區間查詢。
很裸的樹狀數組。
這裏拿cdq來寫,定義結構體:
struct Node{
int type;//操作類型;
int idx;//操作的位置;
int val;//修改的值或者表示第幾個查詢;
bool operator <(const Node& x)const{//優先按照操作位置,其次是修改優於查詢;
if(idx!=x.idx) return idx<x.idx;
return type<x.type;
}
};
修改操作type爲1,然後將查詢操作拆解成兩個,,對於的查詢,type=2,的查詢,type=3。
因爲我們在輸入的時候就是按照操作的時間順序進行輸入的,所以在分治過程中拆成的兩半區間,左區間的所有操作一定是發生在右區間之前的,所以我們只記錄左邊的修改造成的影響,然後將其加到對應的右邊的操作即可。
注意到我們查詢拆成了兩個前綴和的形式,那麼判斷修改對查詢是否造成了影響,只需要
- 在時間線上滿足時間順序
- 修改位置要小於查詢位置,(修改5位置上的數字,只會對查詢纔會產生影響)‘’
P2068 統計和
這道題數列沒有初始值,如果有初始值的話,可以將初始值看成修改操作即可。
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7;
const int maxm=2e4+7;
struct Node{
int type;
int idx;
int val;
bool operator <(const Node& x)const{
if(idx!=x.idx) return idx<x.idx;
return type<x.type;
}
}query[maxm],temp[maxm];
ll ans[maxm];
void CDQ(int l,int r){
if(l==r) return ;
int mid=(l+r)>>1;
CDQ(l,mid);
CDQ(mid+1,r);
int p=l,q=mid+1;
ll sum=0;
int o=0;
while(p<=mid&&q<=r){
if(query[p]<query[q]){//只記錄左邊的修改造成的影響;
if(query[p].type==1) sum+=query[p].val;
temp[o++]=query[p++];
}
else{//說明在此刻,右邊的操作的位置要大於左邊操作的位置,
//那麼由於我們記錄的是前綴和,故這一刻,左邊的修改就需要加到右邊的這次查詢中了。
if(query[q].type==2) ans[query[q].val]-=sum;
else if(query[q].type==3) ans[query[q].val]+=sum;
temp[o++]=query[q++];
}
}
while(p<=mid) temp[o++]=query[p++];
while(q<=r){
if(query[q].type==2) ans[query[q].val]-=sum;
else if(query[q].type==3) ans[query[q].val]+=sum;
temp[o++]=query[q++];
}
for(int i=0;i<o;++i) query[l+i]=temp[i];
}
char s[9];
int main(){
int n,w;
scanf("%d%d",&n,&w);
int l,r,id,x;
int idx=0,time=0;
for(int i=1;i<=w;++i){
scanf("%s",s);
if(s[0]=='x'){
scanf("%d%d",&l,&x);
++idx;
query[idx].type=1,query[idx].idx=l,query[idx].val=x;
}
else{
scanf("%d%d",&l,&r);
++idx;
++time;
query[idx].type=2,query[idx].idx=l-1,query[idx].val=time;
++idx;
query[idx].type=3,query[idx].idx=r,query[idx].val=time;
}
}
CDQ(1,idx);
for(int i=1;i<=time;++i) printf("%lld\n",ans[i]);
return 0;
}