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

原文地址:https://www.cnblogs.com/Jackpei/p/11455150.html