• P2633 Count on a tree


    思路:可持久化线段树+巧妙地树上差分

    提交:1次

    题解:

    我们从根开始,类似主席树板子,一个一个加点,使得从根到叶子节点时一个类似前缀和的主席树,即 (u) 点维护的是 (1)(u) 的路径。
    这样我们就可以在 (u+v-lca(u,v)-fa(lca(u,v))) 这样一颗线段树上二分了。

    #pragma GCC optimize(2)
    #include<cstdio>
    #include<iostream>
    #include<cstring>
    #include<algorithm>
    #define R register int
    using namespace std;
    namespace Luitaryi {
    template<class I> inline I g(I& x) { x=0; register I f=1;
      register char ch; while(!isdigit(ch=getchar())) f=ch=='-'?-1:f;
      do x=x*10+(ch^48); while(isdigit(ch=getchar())); return x*=f;
    } const int N=100010;
    struct node {int ls,rs,sum;}t[N*100]; 
    #define ls(tr) t[tr].ls
    #define rs(tr) t[tr].rs
    #define sum(tr) t[tr].sum
    int n,m,cnt,cc,mxd,ans,tot,rt[N],lg[N];
    int vr[N<<1],nxt[N<<1],fir[N],c[N],a[N],d[N],f[18][N];
    inline void add(int u,int v) {
      vr[++cnt]=v,nxt[cnt]=fir[u],fir[u]=cnt;
      vr[++cnt]=u,nxt[cnt]=fir[v],fir[v]=cnt;
    }
    inline void change(int& tr,int lst,int l,int r,int p) {
      tr=++cc; ls(tr)=ls(lst),rs(tr)=rs(lst),sum(tr)=sum(lst)+1; if(l==r) return; 
      R md=l+r>>1; if(p<=md) change(ls(tr),ls(lst),l,md,p);
      if(p>md) change(rs(tr),rs(lst),md+1,r,p);
      sum(tr)=sum(ls(tr))+sum(rs(tr));
    }
    inline int query(int a,int b,int c,int d,int l,int r,int k) {
      if(l==r) return l; R md=l+r>>1;
      R sz=sum(ls(a))+sum(ls(b))-sum(ls(c))-sum(ls(d));
      if(k<=sz) return query(ls(a),ls(b),ls(c),ls(d),l,md,k);
      return query(rs(a),rs(b),rs(c),rs(d),md+1,r,k-sz);
    }
    inline void dfs(int u) { mxd=max(mxd,d[u]);
      change(rt[u],rt[f[0][u]],1,tot,c[u]);
      for(R i=fir[u];i;i=nxt[i]) { R v=vr[i];
        if(d[v]) continue; d[v]=d[u]+1; f[0][v]=u; dfs(v);
      }
    }
    inline void init() {
      for(R i=2;i<=mxd;++i) lg[i]=lg[i>>1]+1;
      for(R i=1,lim=lg[mxd];i<=lim;++i) for(R j=1;j<=n;++j)
        f[i][j]=f[i-1][f[i-1][j]];
    }
    inline int calc(int u,int v) { if(d[u]<d[v]) swap(u,v);
      for(R i=lg[d[u]];~i;--i) if(d[f[i][u]]>=d[v]) u=f[i][u]; if(u==v) return u;
      for(R i=lg[d[u]];~i;--i) if(f[i][u]!=f[i][v]) u=f[i][u],v=f[i][v];
      return f[0][u];
    }
    inline void main() { 
      g(n),g(m); for(R i=1;i<=n;++i) g(c[i]);
      memcpy(a,c,sizeof(int)*(n+1)); tot=unique(a+1,a+n+1)-a-1; sort(a+1,a+tot+1);
      for(R i=1;i<=n;++i) c[i]=lower_bound(a+1,a+tot+1,c[i])-a;
      for(R i=1,u,v;i<n;++i) g(u),g(v),add(u,v); d[1]=1,dfs(1),init();
      for(R i=1,u,v,k;i<=m;++i) { g(u),u^=ans,g(v),g(k); R tmp=calc(u,v); 
        printf("%d
    ",ans=a[query(rt[u],rt[v],rt[tmp],rt[f[0][tmp]],1,tot,k)]); 
      }
    }
    } signed main() {Luitaryi::main(); return 0;}
    

    2019.08.03
    66

  • 相关阅读:
    小技巧:通过linux一行命令修改ip
    小技巧:textarea文本输入区内实现换行
    set 排序实例
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
    每日日报
  • 原文地址:https://www.cnblogs.com/Jackpei/p/11455150.html
Copyright © 2020-2023  润新知