還是放模板題的一篇部落格。話說今天和分治挺有緣,上午cdq,下午整體分治。
整體分治為何物?一種特殊的分治,和cdq一樣是在樸素分治上加了外掛程式,只不過cdq是參照的歸併,整體是參照的二分查詢。
眾所周知二分查詢可是個好東西,但問題在於它需要一定的預處理,比如讓序列有序。這就讓它在詢問次數很多時顯得有點力不從心,但沒關係,我們有整體二分。
整體二分的要求和cdq一樣,需要允許離線的題目,但它支援修改。而且能用整體二分寫的題目一般都能用樹套樹來解決,但它常數小一點(3到7倍的樣子),寫起來也要簡單一點。
整體二分的思路就是對於值域進行二分,每次得出來的mid不只是針對某乙個詢問,而是針對所有包含了這個點的詢問,這樣就充分利用了我們的算力,這不挺好?
有兩個模板題。第乙個是主席樹的模板題。題意是多次詢問區間第k大,當然可以用主席樹來做,但既然部落格題目是整體二分,那就不寫主席樹吧。做法上就是考慮遞迴處理,假如當前處理的值域是l和r,它們產生了乙個mid,那麼我們就可以把所有處在[l,mid]之中的數的位置標記為1,然後對於每個詢問進行查詢即可,這類題一般用的樹狀陣列維護。邊界就是左右指標重合,這說明這一系列的詢問答案都會是當前的值。
#include#include//#define zczc
using namespace std;
const int n=200010;
const int maxn=1e9;
inline void read(int &wh)
while(w<='9'&&w>='0')
wh*=f;return;
}int m,n,cnt;
#define lowbit (wh&-wh)
int t[n];
inline void change(int wh,int val)
inline int work(int wh)
#undef lowbit
int ans[n];
struct nodeq[n<<1],s1[n<<1],s2[n<<1];
void solve(int wl,int wr,int l,int r)
int mid=l+r>>1,t1=0,t2=0;
for(int i=wl;i<=wr;i++)
else s2[++t2]=q[i];
} for(int i=wl;i<=wr;i++)
for(int i=wl;i<=wr;i++)
for(int i=1;i<=t1;i++)q[wl+i-1]=s1[i];
for(int i=1;i<=t2;i++)q[wl+t1+i-1]=s2[i];
solve(wl,wl+t1-1,l,mid);
solve(wl+t1,wr,mid+1,r);
return;
}signed main()
for(int i=1;i<=n;i++)
solve(1,cnt,-maxn,maxn);
for(int i=1;i<=n;i++)printf("%d\n",ans[i]);
return 0;
}
另乙個是dynamic rankings,題目一樣,只是要求修改。修改其實都還好,由於讀入的時候預設是按時間來的,處理的時候來就按順序可以了。
#include#include//#define zczc
using namespace std;
const int n=100010;
const int maxn=1e9;
inline void read(int &wh)
while(w<='9'&&w>='0')
wh*=f;return;
}inline bool get()
int m,n,cnt,sr[n];
struct nodea[n*3],s1[n*3],s2[n*3];
#define lowbit (wh&-wh)
int t[n],nt[n],ti;
inline void change(int wh,int val,int wt)
return;
}inline int work(int wh,int wt)
return an;
}#undef lowbit
int ans[n];
void solve(int wl,int wr,int l,int r)
ti++;int mid=l+r>>1,t1=0,t2=0;
for(int i=wl;i<=wr;i++)
else s2[++t2]=a[i];
} else
} }for(int i=1;i<=t1;i++)a[wl+i-1]=s1[i];
for(int i=1;i<=t2;i++)a[wl+t1+i-1]=s2[i];
solve(wl,wl+t1-1,l,mid);
solve(wl+t1,wr,mid+1,r);
return;
}signed main()
int s1,s2,s3,nid=0;
for(int i=1;i<=n;i++)
else }
solve(1,cnt,0,maxn);
for(int i=1;i<=nid;i++)printf("%d\n",ans[i]);
return 0;
}
最後說一句,負數域一定要用右移而不是除法! 整體二分專題
何謂整體二分?一般的二分只適用於單個詢問的,如果有很多個詢問,就變成了n 2n 2 n2或更高但整體二分則可以迅速處理多個詢問的問題 首先需要離線,讀入所有詢問 然後我們二分答案,這時候我們將詢問分成兩個部分,如果l r就直接更新答案,否則考慮分治,詢問的答案在左邊的丟到左邊,答案在右邊的則丟到右邊...
學習 整體二分
在?看看整體二分 整體二分是個啥,就是遞迴進行二分答案的操作,按照當前二分出的區間對詢問操作和修改操作進行左右分類。有點類似於歸併排序的樣子,但是需要用個維護區間的資料結構來維護當前詢問區間的區間的查詢和修改操作,每次查詢完當前區間的操作之後,需要清空之前的修改操作。整體二分可以保證會互相影響的操作...
整體二分總結
通常與 cdq 分治同類談論,處理的問題性質本質上有不同 整體二分,顯然整體 同時 處理多個二分查詢,通常帶有修改,我們需要分治處理 solve l,r,l,r 為操作 l,r 中答案均在 l,r 區間內 我們是分治處理 l,mid 操作的前 n 個為新增操作 靜態陣列 掃一遍操作,新增操作時把 v...