可修改主席树&树上可修改主席树—树套树套树!!!

可修改主席树

题目:

Dynamic Rankings(洛谷2617)

!思路:其实树上主席树是把每一棵主席树看做树状数组上的一个点,每次修改log棵主席树,求区间和的时候同样log查询前缀和。

上代码!

#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;
}
View Code

接下来就是调了一天的树上可修改主席树

题目:

网络管理Network

其实就是树上主席树与可修改主席树的结合,(至于为什么我调了一天,因为我弱阿,理直气壮!)。

这份代码还是要常常温习啊,懒得打注释,希望我下次还记得我是怎么写的qaq

#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;
}
View Code

似乎还可以用树剖套主席树套树状数组...

猜你喜欢

转载自www.cnblogs.com/Jessie-/p/9440012.html