[Zjoi2013]K大數查詢——樹套樹
阿新 • • 發佈:2021-02-17
題目
題解
題意大概是給你n個vector,對若干個編號連續的vector進行插入和查詢。
典型的樹套樹唄
先對所有插入的c值建一棵線段樹,然後每個節點再維護一棵線段樹,葉子節點的線段樹存該值在序列中的分佈情況(也就是該值在序列中每個vector中的出現次數,維護區間和),父節點的線段樹存限定區間內的所有c值在序列中的分佈情況,也就是所有子節點的線段樹合併。
插入就是對大線段樹單點修改,對鏈上每個小線段樹進行區間加;
查詢就是利用大線段樹進行二分答案,每次對小線段樹進行區間查詢,總複雜度。
樹套樹的碼量名不虛傳,好在我板子打得優美,少除錯。
程式碼
#include<cstdio> #include<cstring> #include<iostream> #include<algorithm> #include<cmath> #include<vector> #include<queue> #include<map> #define ll long long #define MAXN 50005 #define MAXP 20000005 using namespace std; inline ll read(){ ll x=0;bool f=1;char s=getchar(); while((s<'0'||s>'9')&&s>0){if(s=='-')f^=1;s=getchar();} while(s>='0'&&s<='9')x=(x<<1)+(x<<3)+s-'0',s=getchar(); return f?x:-x; } int n; struct itn{ //小線段樹 int ls,rs,lz;ll a; itn(){ls=rs=lz=a=0;} }t[MAXP]; int IN; inline void pushd(int x,int l,int r){ if(t[x].lz>0){ if(l==r){t[x].lz=0;return;} int mid=(l+r)>>1; if(!t[x].ls)t[x].ls=++IN,t[IN]=itn(); t[t[x].ls].a+=(1ll+mid-l)*t[x].lz,t[t[x].ls].lz+=t[x].lz; if(!t[x].rs)t[x].rs=++IN,t[IN]=itn(); t[t[x].rs].a+=(0ll+r-mid)*t[x].lz,t[t[x].rs].lz+=t[x].lz; t[x].lz=0; } } inline void addt(int x,int l,int r,int a,int b){ if(l==a&&r==b){ t[x].a+=r-l+1,t[x].lz++; return; } int mid=(l+r)>>1;pushd(x,l,r); if(a<=mid){ if(!t[x].ls)t[x].ls=++IN,t[IN]=itn(); addt(t[x].ls,l,mid,a,min(b,mid)); } if(b>mid){ if(!t[x].rs)t[x].rs=++IN,t[IN]=itn(); addt(t[x].rs,mid+1,r,max(a,mid+1),b); } t[x].a=t[t[x].ls].a+t[t[x].rs].a; } inline ll sch(int x,int l,int r,int a,int b){ if(!x)return 0; if(l==a&&r==b)return t[x].a; int mid=(l+r)>>1;pushd(x,l,r); ll res=0; if(a<=mid)res+=sch(t[x].ls,l,mid,a,min(b,mid)); if(b>mid)res+=sch(t[x].rs,mid+1,r,max(a,mid+1),b); return res; } struct ITN{ //大線段樹 int ls,rs,id; }tr[MAXN<<4]; int NN; inline void add(int x,int l,int r,int a,int b,int z){ if(l==r){addt(tr[x].id,1,n,a,b);return;} int mid=(l+r)>>1; if(z<=mid){ if(!tr[x].ls)tr[x].ls=++NN,tr[tr[x].ls].id=++IN,t[IN]=itn(); add(tr[x].ls,l,mid,a,b,z); } else{ if(!tr[x].rs)tr[x].rs=++NN,tr[tr[x].rs].id=++IN,t[IN]=itn(); add(tr[x].rs,mid+1,r,a,b,z); } addt(tr[x].id,1,n,a,b); } inline int query(int x,int l,int r,int a,int b,ll c){ if(l==r)return l; int mid=(l+r)>>1;ll z=sch(tr[tr[x].rs].id,1,n,a,b); if(z>=c)return query(tr[x].rs,mid+1,r,a,b,c); else return query(tr[x].ls,l,mid,a,b,c-z); } signed main() { n=read(); tr[++NN].id=++IN; for(int M=read();M--;){ int opt=read(),a=read(),b=read();ll c=read(); if(opt==1)add(1,-n,n,a,b,c); else printf("%d\n",query(1,-n,n,a,b,c)); } return 0; }