主席樹,喵~
阿新 • • 發佈:2018-04-28
str hdu4417 ffi pac 直接 發現 names 很多 Go
稍微總結一下主席樹吧
Too Difficult!搞了一天搞出一大堆怎麽令人悲傷的辣雞代碼。總之先總結一下吧,以後碰到這種問題直接拿去毒害隊友好了。
Lv.1 最基本的操作
區間k大值
區間內有多少個數字小於等於x
query 操作了解一下 int query(int new_k,int old_k,int l,int r,int x) { // cnt <= x if(x<l) return 0; // 這個地方比較喜。小心點。 if(l==r) return sum[new_k]-sum[old_k]; int mid=(l+r)>>1; if(mid<x) return sum[lson[new_k]]-sum[lson[old_k]]+query(rson[new_k],rson[old_k],mid+1,r,x); else return query(lson[new_k],lson[old_k],l,mid,x); }
兩道入門題:POJ2104,HDU4417
目前對主席樹很naive的理解:主席樹相當於對每一個前綴都維護一個線段樹,然後發現相鄰兩棵線段樹長得好像哎!然後就是資源重復利用了。
既然是維護每一個前綴,所以,我們不僅能拿主席樹來施展線性結構,還能施展樹狀結構!比如說我們可以查詢樹上兩點間路徑點權的k小值。
Lv.2 樹上路徑上點權k小值
栗子:SPOJ-COT
線性結構上
iterval(l,r)=T(r)-T(l-1)
樹狀結構上
path(u,v) = T(u)+T(v)-T(lca)-T(Parent of lca)
Lv.2 矩形內有多少個點
給出很多個點。Q組詢問,每組詢問查詢一個矩形內有幾個點。
按橫坐標排序,把縱坐標放到主席樹上,然後就相當於區間內有多少個數字小於等於x啦!
CF853C
把細節考慮好!還是很友好的。
#include <iostream> #include <algorithm> using namespace std; const int N=6000000+10; #define f(x) (1LL*x*(x-1)/2) typedef long long LL; int lson[N],rson[N],sum[N],root[N],pid; int n,q,p[N]; void build(int &k,int l,int r){ k=++pid; if(l==r) return; int mid=(l+r)>>1; build(lson[k],l,mid); build(rson[k],mid+1,r); } void change(int old,int &k,int l,int r,int pos,int x) { k=++pid; lson[k]=lson[old],rson[k]=rson[old],sum[k]=sum[old]+x; if(l==r) return; int mid=(l+r)>>1; if(pos<=mid) change(lson[k],lson[k],l,mid,pos,x); else change(rson[k],rson[k],mid+1,r,pos,x); } int query(int new_k,int old_k,int l,int r,int x) { // cnt <= x if(x<l) return 0; if(l==r) return sum[new_k]-sum[old_k]; int mid=(l+r)>>1; if(mid<x) return sum[lson[new_k]]-sum[lson[old_k]]+query(rson[new_k],rson[old_k],mid+1,r,x); else return query(lson[new_k],lson[old_k],l,mid,x); } int count(int x1,int x2,int y1,int y2) { // if(x1>x2||y1>y2) return 0; int cnt1 = query(root[x2],root[x1-1],1,n,y1-1); int cnt2 = query(root[x2],root[x1-1],1,n,y2); return cnt2-cnt1; } int main(){ scanf("%d%d",&n,&q); for(int i=1;i<=n;i++) { scanf("%d",&p[i]); } build(root[0],1,n); for(int i=1;i<=n;i++) { change(root[i-1],root[i],1,n,p[i],1); } for(int i=1;i<=q;i++){ int l,d,r,u; scanf("%d%d%d%d",&l,&d,&r,&u); int LU = count(1,l-1,u+1,n); int LD = count(1,l-1,1,d-1); int RU = count(r+1,n,u+1,n); int RD = count(r+1,n,1,d-1); int L = l-1; int U = n-u; int R = n-r; int D = d-1; LL A = f(L)+f(R)+f(U)+f(D); LL B = f(LU)+f(LD)+f(RU)+f(RD); LL ret = 1LL*n*(n-1)/2-(A-B); printf("%lld\n", ret); } }
以上,於4/28,mark一下。
之後,待補的坑:
- BIT套主席樹
- 主席樹的區間更新
學數據結構是不可能學數據結構的,這輩子都不可能學數據結構!
主席樹,喵~