主席树——树链上第k大spoj COT
Posted zsben991126
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了主席树——树链上第k大spoj COT相关的知识,希望对你有一定的参考价值。
首先要求第k大就想到用主席树来处理
但是不能直接用树链剖分的dfs序来维护,因为一条链对应的dfs下标可能是断开的几段,无法用权值线段树来维护
那么久维护每个点到根节点的全值线段树,结点u的权值线段树记录了其到根节点路径上数值的出现次数
主席树相当于维护了一个前缀和,由树上前缀和可以分析出u->v路径上对应的那棵权值线段树应该是
T[u]+T[v]-T[lca]-T[fa[lca]]
所以只要在dfs过程中,结点u依赖fa[u]进行更新主席树即可
那么问题解变成了每个结点u上维护到root的权值线段树,然后每次询问求lca(u,v),再按照上述公式去主席树上查询第k大
求lca可以用树剖,也可以倍增。。
#include <bits/stdc++.h> #define maxn 100005 using namespace std; const int N = 1e5+100; struct Node{int lc,rc,sum;}T[N*20]; int fa[2*N][30], dep[2*N], vis[N]; int a[N], b[N], tot, cnt, head[N], len; struct node{int to, next;} p[2*N]; void init(){ memset(head,-1,sizeof(head)); memset(vis,0,sizeof(vis)); cnt=0; return ; } void add(int u,int v){ p[cnt].to=v,p[cnt].next=head[u];head[u]=cnt++; p[cnt].to=u,p[cnt].next=head[v];head[v]=cnt++; return ; } int size,rt[N]; int build(int l,int r){ int now=++size; T[now].lc=T[now].rc=T[now].sum=0; if(l==r)return now; int mid=l+r>>1; T[now].lc=build(l,mid); T[now].rc=build(mid+1,r); return now; } int update(int l,int r,int last,int pos){//更新到pos点 int now=++size; T[now]=T[last];T[now].sum++; if(l==r)return now; int mid=l+r>>1; if(pos<=mid)T[now].lc=update(l,mid,T[last].lc,pos); else T[now].rc=update(mid+1,r,T[last].rc,pos); return now; } int query(int e1,int e2,int s1,int s2,int l,int r,int k){ if(l==r)return l; int mid=l+r>>1; int sum=T[T[e1].lc].sum+T[T[e2].lc].sum-T[T[s1].lc].sum-T[T[s2].lc].sum; if(k<=sum)return query(T[e1].lc,T[e2].lc,T[s1].lc,T[s2].lc,l,mid,k); else return query(T[e1].rc,T[e2].rc,T[s1].rc,T[s2].rc,mid+1,r,k-sum); } void dfs(int u,int d,int f,int root){ vis[u]=1,dep[u]=d,fa[u][0]=f; rt[u]=update(1,len,root,a[u]); for(int i=head[u];i!=-1;i=p[i].next){ int v=p[i].to; if(vis[v]) continue; dfs(v,d+1,u,rt[u]); } } int f[maxn],son[maxn],d[maxn],siz[maxn]; void dfs1(int x,int pre,int deep){ f[x]=pre;siz[x]=1;d[x]=deep; for(int i=head[x];i!=-1;i=p[i].next){ int y=p[i].to; if(y==pre)continue; dfs1(y,x,deep+1); siz[x]+=siz[y]; if(siz[y]>siz[son[x]])son[x]=y; } } int id[maxn],rk[maxn],idx,top[maxn]; void dfs2(int x,int tp){ top[x]=tp;id[x]=++idx;rk[idx]=x; if(son[x])dfs2(son[x],tp); for(int i=head[x];i!=-1;i=p[i].next){ int y=p[i].to; if(y!=son[x] && y!=f[x])dfs2(y,y); } } int Query(int x,int y){ while(top[x]!=top[y]){ if(d[top[x]]<d[top[y]])swap(x,y); x=f[top[x]]; } if(id[x]>id[y])swap(x,y); return x; } int main(){ int t, n, q; scanf("%d %d", &n, &q); for(int i=1; i<=n; i++) scanf("%d", &a[i]), b[i]=a[i]; sort(b+1,b+n+1); len=unique(b+1,b+n+1)-(b+1); tot=0; rt[0]=build(1,len); for(int i=1; i<=n; i++) a[i]=lower_bound(b+1,b+len+1,a[i])-(b); init(); for(int i=0;i<n-1;i++){ int x, y; scanf("%d %d", &x, &y); add(x,y); } dfs(1,1,0,rt[0]);dfs1(1,0,1),dfs2(1,1); int ans=0; while(q--){ int l, r, x; scanf("%d %d %d", &l, &r, &x);l^=ans; int pos=Query(l,r); printf("%d\n",ans=b[query(rt[l],rt[r],rt[pos],rt[fa[pos][0]],1,len,x)]); } return 0; }
以上是关于主席树——树链上第k大spoj COT的主要内容,如果未能解决你的问题,请参考以下文章
spoj COT - Count on a tree (树上第K小 LCA+主席树)
SPOJ COT Count on a tree(树上主席树 + LCA 求路径第k小)题解
Count on a tree SPOJ 主席树+LCA(树链剖分实现)(两种存图方式)