BZOJ2588 - Count on a tree
2017-12-07 20:33
218 查看
原题链接
最后一次查询不要输出\n,否则会PE。
题意简述
给出一棵带点权的n(n≤105)个节点的树,Q(Q≤105)次询问路径(u,v)上第k小的点权值。分析
记节点到根的点权和为dst,则(u,v)上的点权和为dst[u]+dst[v]−dst[lca(u,v)]−dst[fa[lca(u,v)]]。相似的,对于每个节点,我们用权值线段树记录该节点到根的路径上的点权,这样就可以得到路径(u,v)上的点权了。考虑到每个节点的线段树相当于在其父节点的线段树上进行单点+1,我们可以用可持久化线段树来解决这道题。实现
与普通的可持久化线段树差别不大,只是在查询的时候要多传几个参数。代码
//Count on a tree #include <cstdio> #include <algorithm> using namespace std; inline char gc() { static char now[1<<16],*S,*T; if(S==T) {T=(S=now)+fread(now,1,1<<16,stdin); if(S==T) return EOF;} return *S++; } inline int read() { int x=0,f=1; char ch=gc(); while(ch<'0'||'9'<ch) {if(ch=='-') f=-1; ch=gc();} while('0'<=ch&&ch<='9') x=x*10+ch-'0',ch=gc(); return x*f; } int const N=1e5+10; int n,m,v ; int num,map ; struct rec{int v,id;} a0 ; bool cmpV(rec x,rec y) {return x.v<y.v;} int cnt,h ; struct edge{int v,nxt; edge(int u=0,int v1=0){v=v1,nxt=h[u],h[u]=cnt;}} ed[N<<1]; #define s sg[s0] int sgCnt,rt ; struct seg{int cnt; int L,R;} sg[N*20]; void update(int s0) {s.cnt=sg[s.L].cnt+sg[s.R].cnt;} void ins(int &s0,int fr,int to,int v) { sg[++sgCnt]=s; s0=sgCnt; if(fr==to) {s.cnt++; return;} int mid=fr+to>>1; if(v<=mid) ins(s.L,fr,mid,v); else ins(s.R,mid+1,to,v); update(s0); } int query(int s1,int s2,int s3,int s4,int fr,int to,int k) { if(fr==to) return fr; int cntL=sg[sg[s1].L].cnt+sg[sg[s2].L].cnt-sg[sg[s3].L].cnt-sg[sg[s4].L].cnt; int mid=fr+to>>1; if(k<=cntL) return query(sg[s1].L,sg[s2].L,sg[s3].L,sg[s4].L,fr,mid,k); else return query(sg[s1].R,sg[s2].R,sg[s3].R,sg[s4].R,mid+1,to,k-cntL); } int fa [20],dpt ; void trform(int u) { ins(rt[u]=rt[fa[u][0]],1,num,v[u]); for(int i=1;i<=17;i++) fa[u][i]=fa[fa[u][i-1]][i-1]; for(int i=h[u];i;i=ed[i].nxt) { int v=ed[i].v; if(v!=fa[u][0]) fa[v][0]=u,dpt[v]=dpt[u]+1,trform(v); } } int lca(int u,int v) { if(dpt[u]<dpt[v]) swap(u,v); for(int i=17;i>=0;i--) if(dpt[fa[u][i]]>=dpt[v]) u=fa[u][i]; for(int i=17;i>=0;i--) if(fa[u][i]!=fa[v][i]) u=fa[u][i],v=fa[v][i]; return u==v?u:fa[u][0]; } int main() { n=read(); m=read(); for(int i=1;i<=n;i++) a0[i].v=read(),a0[i].id=i; sort(a0+1,a0+n+1,cmpV); num=0; for(int i=1;i<=n;i++) { if(a0[i-1].v!=a0[i].v) map[++num]=a0[i].v; v[a0[i].id]=num; } cnt=0; for(int i=1;i<=n-1;i++) { int u=read(),v=read(); ed[++cnt]=edge(u,v); ed[++cnt]=edge(v,u); } rt[0]=sgCnt=0; fa[1][0]=0,dpt[1]=1,trform(1); int ans=0; for(int owo=1;owo<=m;owo++) { int u=read()^ans,v=read(),k=read(); int w=lca(u,v); printf("%d",ans=map[query(rt[u],rt[v],rt[w],rt[fa[w][0]],1,num,k)]); if(owo!=m) printf("\n"); } return 0; }
注意
本题强制在线,查询时仅需要将u异或上lastans即可。非强制在线的原题来自SPOJ.com - Problem COT。最后一次查询不要输出\n,否则会PE。
相关文章推荐
- 【bzoj 2588】Count on a tree(可持久化线段树+LCA)
- BZOJ2588 Spoj 10628. Count on a tree
- BZOJ_2588_Spoj 10628. Count on a tree_树剖+主席树
- [主席树] BZOJ 2588 Spoj 10628. Count on a tree
- bzoj 2588: Spoj 10628. Count on a tree(树上主席树)
- [BZOJ2588][SPOJ10628]Count on a tree
- BZOJ-2588-Count-on-a-tree-SPOJ10628-LCA+主席树
- bzoj 2588 Spoj 10628. Count on a tree
- BZOJ 2588 Spoj 10628 Count on a tree | 树上主席树
- 【bzoj2588】Spoj 10628. Count on a tree
- bzoj 2588: Spoj 10628. Count on a tree LCA+主席树
- [BZOJ2588][Spoj10628]Count on a tree(树上主席树)
- BZOJ 2588: Spoj 10628. Count on a tree
- [bzoj 2588] Spoj 10628. Count on a tree:函数式线段树
- 【BZOJ 2588】 Spoj 10628. Count on a tree|树上K大|树链剖分|主席树
- BZOJ[2588]Count on a tree 主席树
- AC日记——Count on a tree bzoj 2588
- Bzoj2588 Count on a tree
- BZOJ 2588 Spoj 10628. Count on a tree 主席树
- [BZOJ]2588 Spoj 10628. Count on a tree 树链第k大 PE的进来看看