可修改主席树&树上可修改主席树—树套树套树!!!
可修改主席树
题目:
Dynamic Rankings(洛谷2617)
!思路:其实树上主席树是把每一棵主席树看做树状数组上的一个点,每次修改log棵主席树,求区间和的时候同样log查询前缀和。
上代码!
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=2e4+5; int n,m,rt[N],root[N],q[N],cnt,a[N],b[N],tot; struct node{int l,r,num;}t[N*100]; struct data{int x,y,k;}Q[N]; inline int getid(int x){return lower_bound(b+1,b+1+cnt,x)-b;} inline int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;return f*x;} void update(int l,int r,int &x,int y,int pos,int v){ t[x=++tot]=t[y];t[x].num+=v; if(l==r)return;int mid=(l+r)>>1; if(pos<=mid)update(l,mid,t[x].l,t[y].l,pos,v); else update(mid+1,r,t[x].r,t[y].r,pos,v); } inline void change(int p,int v){ for(int i=p;i<=n;i+=i&-i)update(1,cnt,rt[i],rt[i],a[p],v); } inline int cal(int x){ int sum=0; for(int i=x;i;i-=i&-i)sum+=t[t[q[i]].l].num;return sum; } inline int query(int x,int y,int k){ for(int i=x;i;i-=i&-i)q[i]=rt[i]; for(int i=y;i;i-=i&-i)q[i]=rt[i]; int l=1,r=cnt,qx=x,qy=y;x=root[x];y=root[y]; while(l<r){ int sum=cal(qy)-cal(qx)+t[t[y].l].num-t[t[x].l].num; int mid=(l+r)>>1; if(k<=sum){ for(int i=1;i<=n;i++)q[i]=t[q[i]].l; x=t[x].l;y=t[y].l;r=mid; } else{ for(int i=1;i<=n;i++)q[i]=t[q[i]].r; x=t[x].r;y=t[y].r;l=mid+1;k-=sum; } } return l; } int main() { n=read();m=read();for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i];cnt=n; for(int i=1;i<=m;i++){ char ch;cin>>ch; if(ch=='Q')Q[i].x=read(),Q[i].y=read(),Q[i].k=read(); if(ch=='C')Q[i].x=read(),Q[i].k=read(),b[++cnt]=Q[i].k; } sort(b+1,b+1+cnt);cnt=unique(b+1,b+1+cnt)-b-1;for(int i=1;i<=n;i++)a[i]=getid(a[i]); for(int i=1;i<=n;i++)update(1,cnt,root[i],root[i-1],a[i],1); for(int i=1;i<=m;i++){ if(Q[i].y==0){ change(Q[i].x,-1);a[Q[i].x]=getid(Q[i].k);change(Q[i].x,1); } else{ printf("%d\n",b[query(Q[i].x-1,Q[i].y,Q[i].k)]); } } return 0; }
接下来就是调了一天的树上可修改主席树!
题目:
网络管理Network
其实就是树上主席树与可修改主席树的结合,(至于为什么我调了一天,因为我弱阿,理直气壮!)。
这份代码还是要常常温习啊,懒得打注释,希望我下次还记得我是怎么写的qaq
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
#include<bits/stdc++.h> #define _(d) while(d(isdigit(ch=getchar()))) using namespace std; const int N=80005; int n,m,d[N],fa[N][22],head[N],ne[N<<1],to[N<<1],cnt,tot,rt[N],q[N],a[N],b[N<<1],vis[N],dfn[N],tt,num[N],sz[N]; struct node{int l,r,num;}t[N*120];struct data{int k,a,b;}Q[N]; inline int read(){int x,f=1;char ch;_(!)ch=='-'?f=-1:f;x=ch-48;_()x=x*10+ch-48;return f*x;} inline void insert(int u,int v){ne[++tot]=head[u];head[u]=tot;to[tot]=v;} inline int getid(int x){return lower_bound(b+1,b+1+cnt,x)-b;} void update(int l,int r,int &x,int y,int pos,int v){ if(!x)x=++tot;t[x]=t[y];t[x].num+=v; if(l==r)return;int mid=(l+r)>>1; if(pos<=mid)update(l,mid,t[x].l,t[y].l,pos,v); else update(mid+1,r,t[x].r,t[y].r,pos,v); } void dfs(int x){ //update(1,cnt,root[x],root[fa[x][0]],a[x],1); dfn[x]=++tt;num[tt]=x;sz[x]=1; for(int i=head[x];i;i=ne[i]){ if(to[i]==fa[x][0])continue; d[to[i]]=d[x]+1;fa[to[i]][0]=x; dfs(to[i]);sz[x]+=sz[to[i]]; } } inline int Lca(int x,int y){ if(d[x]<d[y])swap(x,y); for(int i=20;i>=0;i--)if(d[fa[x][i]]>=d[y])x=fa[x][i]; if(x==y)return x; for(int i=20;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i]; return fa[x][0]; } inline void change(int p,int x,int v){//if(dfn[p]==0)printf("#%d %d %d ",p,x,sz[x]); for(int i=dfn[p];i<=n;i+=i&-i)update(1,cnt,rt[i],rt[i],a[x],v); } inline void getq(int x){for(int i=dfn[x];i;i-=i&-i)q[i]=rt[i],vis[i]=1;} inline int cal(int x){int sum=0;for(int i=dfn[x];i;i-=i&-i)sum+=t[t[q[i]].l].num,vis[i]=0;return sum;} inline void cagl(int x){for(int i=dfn[x];i;i-=i&-i)if(!vis[i])q[i]=t[q[i]].l,vis[i]=1;} inline void cagr(int x){for(int i=dfn[x];i;i-=i&-i)if(!vis[i])q[i]=t[q[i]].r,vis[i]=1;} inline int query(int x,int y,int a,int b,int k){ getq(x);getq(y);getq(a);getq(b);//printf("#"); int l=1,r=cnt,sum; while(l<r){ int mid=(l+r)>>1; sum=cal(x)+cal(y)-cal(a)-cal(b); if(k<=sum){ cagl(x);cagl(y);cagl(a);cagl(b);r=mid; } else{ cagr(x);cagr(y);cagr(a);cagr(b);l=mid+1;k-=sum; } } return l; } int main() { n=read();m=read();for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i];cnt=n; for(int i=1;i<n;i++){int x,y;x=read();y=read();insert(x,y);insert(y,x);}tot=0; for(int i=1;i<=m;i++){ Q[i].k=read();Q[i].a=read();Q[i].b=read(); if(Q[i].k==0)b[++cnt]=Q[i].b; } sort(b+1,b+1+cnt);cnt=unique(b+1,b+1+cnt)-b-1;for(int i=1;i<=n;i++)a[i]=getid(a[i]);dfn[n+1]=n+1;num[n+1]=n+1; d[1]=1;dfs(1);for(int i=1;i<=20;i++)for(int j=1;j<=n;j++)fa[j][i]=fa[fa[j][i-1]][i-1]; for(int i=1;i<=n;i++){change(i,i,1);change(num[dfn[i]+sz[i]],i,-1);} for(int i=1;i<=m;i++){ if(Q[i].k==0){ change(Q[i].a,Q[i].a,-1);change(num[dfn[Q[i].a]+sz[Q[i].a]],Q[i].a,1); a[Q[i].a]=getid(Q[i].b);change(Q[i].a,Q[i].a,1);change(num[dfn[Q[i].a]+sz[Q[i].a]],Q[i].a,-1); } else { int lca=Lca(Q[i].a,Q[i].b);int k=d[Q[i].a]+d[Q[i].b]-2*d[lca]-Q[i].k+2; if(k<1){puts("invalid request!");continue;} printf("%d\n",b[query(Q[i].a,Q[i].b,lca,fa[lca][0],k)]); } } return 0; }
似乎还可以用树剖套主席树套树状数组...