• [BZOJ4771]七彩树(主席树)


    https://blog.csdn.net/KsCla/article/details/78249148

    用类似经典的链上区间颜色计数问题的做法,这个题可以看成是询问DFS在[L[x],R[x]]中,深度在[dep[x],dep[x]+d]中,上一个同色点在[0,L[x]-1]中的点的个数。这是个三维数点问题,如果不强制在线的话,可以离线解决一维,主席树解决两维。

    强制在线的话,其实还有一个“离线”方法:在所有询问前就将所有答案全部算好。

    考虑两个同色点,在不考虑深度的情况下,它们所贡献的点是它们到根的链的并。对于链并问题,往往用set维护dfs序,然后插入点时处理dfs序相邻的两项的信息(差分),可以通过线段树来支持动态差分。

    现在考虑深度,按深度建主席树即可。

    讲的并不清楚,具体还是看上面的题解吧。代码应该还是比较好理解的。

     1 #include<set>
     2 #include<cstdio>
     3 #include<vector>
     4 #include<algorithm>
     5 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     6 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     7 typedef long long ll;
     8 using namespace std;
     9 
    10 const int N=100010,M=10000010;
    11 int T,n,m,u,v,cnt,ans,tim,nd,x,d,co[N],dep[N],h[N],to[N],nxt[N];
    12 int ls[M],rs[M],sm[M],fa[N][19],L[N],R[N],pos[N],rt[N];
    13 vector<int>a[N];
    14 set<int>c[N];
    15 
    16 void add(int u,int v){ to[++cnt]=v; nxt[cnt]=h[u]; h[u]=cnt; }
    17 
    18 void dfs(int x){
    19     rep(i,1,18) fa[x][i]=fa[fa[x][i-1]][i-1];
    20     dep[x]=dep[fa[x][0]]+1; L[x]=++tim;
    21     pos[tim]=x; a[dep[x]].push_back(x);
    22     For(i,x) dfs(k=to[i]); R[x]=tim;
    23 }
    24 
    25 int lca(int u,int v){
    26     if (dep[u]<dep[v]) swap(u,v);
    27     int t=dep[u]-dep[v];
    28     for (int i=18; ~i; i--) if (t&(1<<i)) u=fa[u][i];
    29     if (u==v) return u;
    30     for (int i=18; ~i; i--) if (fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i];
    31     return fa[u][0];
    32 }
    33 
    34 void ins(int &x,int y,int L,int R,int pos,int k){
    35     x=++nd; ls[x]=ls[y]; rs[x]=rs[y]; sm[x]=sm[y]+k;
    36     if (L==R) return;
    37     int mid=(L+R)>>1;
    38     if (pos<=mid) ins(ls[x],ls[y],L,mid,pos,k);
    39         else ins(rs[x],rs[y],mid+1,R,pos,k);
    40 }
    41 
    42 int que(int x,int y,int L,int R,int l,int r){
    43     if (!y) return 0;
    44     if (L==l && r==R) return sm[y]-sm[x];
    45     int mid=(L+R)>>1;
    46     if (r<=mid) return que(ls[x],ls[y],L,mid,l,r);
    47     else if (l>mid) return que(rs[x],rs[y],mid+1,R,l,r);
    48         else return que(ls[x],ls[y],L,mid,l,mid)+que(rs[x],rs[y],mid+1,R,mid+1,r);
    49 }
    50 
    51 int main(){
    52     freopen("bzoj4771.in","r",stdin);
    53     freopen("bzoj4771.out","w",stdout);
    54     for (scanf("%d",&T); T--; ){
    55         scanf("%d%d",&n,&m);
    56         rep(i,1,n) h[i]=0; cnt=tim=ans=nd=0;
    57         rep(i,1,n) scanf("%d",&co[i]);
    58         rep(i,2,n) scanf("%d",&fa[i][0]),add(fa[i][0],i);
    59         rep(i,1,n) a[i].clear(),c[co[i]].clear();
    60         dfs(1);
    61         rep(i,1,n){
    62             rt[i]=rt[i-1]; int ed=a[i].size()-1;
    63             rep(j,0,ed){
    64                 int x=a[i][j]; ins(rt[i],rt[i],1,n,L[x],1); c[co[x]].insert(L[x]);
    65                 set<int>::iterator it=c[co[x]].find(L[x]);
    66                 int pre=0,suf=0; it++;
    67                 if (it!=c[co[x]].end()) suf=*it; it--;
    68                 if (it!=c[co[x]].begin()) it--,pre=*it;
    69                 if (pre && suf) ins(rt[i],rt[i],1,n,L[lca(pos[pre],pos[suf])],1);
    70                 if (pre) ins(rt[i],rt[i],1,n,L[lca(pos[pre],x)],-1);
    71                 if (suf) ins(rt[i],rt[i],1,n,L[lca(pos[suf],x)],-1);
    72             }
    73         }
    74         while (m--){
    75             scanf("%d%d",&x,&d); x^=ans; d^=ans;
    76             printf("%d
    ",ans=que(rt[dep[x]-1],rt[dep[x]+d],1,n,L[x],R[x]));
    77         }
    78     }
    79     return 0;
    80 }
  • 相关阅读:
    约瑟夫问题
    LCIS(最长公共上升子序列)
    Spfa求负环
    裴蜀(贝祖)定理
    Tarjan算法之简单缩点
    树形dp-二次扫描+换根
    sys.path.insert
    python学习之路(十二)
    python学习之路(十一)
    python学习之路(十)
  • 原文地址:https://www.cnblogs.com/HocRiser/p/10104799.html
Copyright © 2020-2023  润新知