BZOJ2588: Spoj 10628. Count on a tree
裸的树上主席树。一般的主席树每个节点相当于一个前缀和,树上主席树每个节点相当于到根的和,可持久化的时候以树上的父亲为上一个版本。
注意最后一行行末不能输出换行,否则会PE。
upd: 用可持久化trie重写了一遍,和主席树本质相同写法不同,变快了。
#include<algorithm> #include<cstdio> #define lb lower_bound using namespace std; const int N=1e5+5; typedef struct node*ptr; struct node{ ptr i,j;int s; }e[N*17]; ptr a=e,f[N]; void ins(int j,ptr*o){ for(int i=16;~i;--i){ *++a=**o,*o=a; if(j>>i&1)o=&(*o)->j; else ++(*o)->s,o=&(*o)->i; } } int ask(int k,ptr s,ptr t,ptr u,ptr v){ int j=0; for(int i=16;~i;--i){ int l=s->s+t->s-u->s-v->s; if(k<=l)s=s->i,t=t->i,u=u->i,v=v->i; else k-=l,j|=1<<i,s=s->j,t=t->j,u=u->j,v=v->j; } return j; } struct edge{ int v;edge*s; }z[N*2]; edge*b=z,*h[N]; void ins(int u,int v){ edge s={v,h[u]}; *(h[u]=b++)=s; } typedef int arr[N]; arr w,p,d,r,y,c,g; void dfs1(int u){ f[u]=f[p[u]]; ins(w[u],f+u); r[u]=1; for(edge*i=h[u];i;i=i->s) if(i->v!=p[u]){ d[i->v]=d[p[i->v]=u]+1; dfs1(i->v); r[u]+=r[i->v]; if(r[i->v]>r[c[u]]) c[u]=i->v; } } int lca(int s,int t){ for(;y[s]!=y[t];s=p[y[s]]) if(d[y[s]]<d[y[t]])s^=t,t^=s,s^=t; return d[s]<d[t]?s:t; } struct buf{ char z[1<<23],*s; char e[9<<17],*p; buf():s(z),p(e){ z[fread(z,1,sizeof z,stdin)]=0; } ~buf(){fwrite(e,1,p-e,stdout);} operator int(){ int x=0; while(*s<48)++s; while(*s>32) x=x*10+*s++-48; return x; } void out(int x){ static char z[12]; char*i=z; if(!x)*p++=48; else{ while(x){ int y=x/10; *i++=x-y*10+48,x=y; } while(i!=z)*p++=*--i; } } }it; int main(){ *(*f=e)=(node){e,e}; int n=it,m=it; for(int i=1;i<=n;++i) g[i-1]=w[i]=it; sort(g,g+n); for(int i=1;i<=n;++i) w[i]=lb(g,g+n,w[i])-g; for(int i=2;i<=n;++i){ int s=it,t=it; ins(s,t),ins(t,s); } dfs1(1); for(int i=1;i<=n;++i) if(c[p[i]]!=i) for(int j=i;j;j=c[j])y[j]=i; int l=0; while(m--){ int s=it^l,t=it,u=lca(s,t); it.out(l=g[ask(it,f[s],f[t],f[u],f[p[u]])]); if(m)*it.p++=10; } }