Luogu 3302 森林(树上维护主席树)
Posted 一个废物的blog
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Luogu 3302 森林(树上维护主席树)相关的知识,希望对你有一定的参考价值。
P3302 [SDOI2013]森林 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)P3302 [SDOI2013]森林 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
大概就是要在树上搞第k小吗,还要支持合并
讲实话第一反应树剖+线段树维护,然后就傻掉了
讲正解:
每一个节点开一颗主席树维护从该节点到根节点的路径信息
然后x->y的路径就很明显要用到LCA
至于第二问,我们采用启发式合并,复杂度好像可以均摊到logn,每次将小的向大的合并。
//code by SPzos #include<bits/stdc++.h> #define fo(i,j,k) for(register int i=j;i<=k;++i) using namespace std; const int N=8e4+5; inline int read(){ int x=0,f=1;char ch=getchar(); while(ch>\'9\'||ch<\'0\'){ if(ch==\'-\') f=-1; ch=getchar(); } while(ch>=\'0\'&&ch<=\'9\') x=x*10+ch-\'0\',ch=getchar(); return x*f; } struct edge{ int v,nxt; }e[N<<2]; int cnt,head[N<<2],n,m,T,a[N],b[N],col[N],lg[N]; inline void add(int x,int y){ e[++cnt].nxt=head[x]; e[cnt].v=y; head[x]=cnt; } struct node{ int l,r,sum; }t[N*105]; int top,f[N][35],deep[N],size[N],root[N],tot,kk; void build(int &pos,int pre,int l,int r,int wi){ t[pos=++top]=t[pre]; t[pos].sum++; if(l==r) return; int mid=(l+r)>>1; if(wi<=mid) build(t[pos].l,t[pre].l,l,mid,wi); else build(t[pos].r,t[pre].r,mid+1,r,wi); return; } void dfs(int u,int fa,int rt){ build(root[u],root[fa],1,tot,a[u]); deep[u]=deep[fa]+1;f[u][0]=fa; size[rt]++;col[u]=rt; for(int i=1;i<=18;i++) f[u][i]=f[f[u][i-1]][i-1]; for(int i=head[u];i;i=e[i].nxt) if(e[i].v!=fa) dfs(e[i].v,u,rt); return; } int lca(int u,int v){ if(deep[u]<deep[v]) swap(u,v); while(deep[u]>deep[v]) u=f[u][lg[deep[u]-deep[v]]]; if(u==v) return u; for(int i=lg[deep[u]];i>=0;i--) if(f[u][i]!=f[v][i]) u=f[u][i],v=f[v][i]; return f[u][0]; } int Answer(int u,int v,int og,int fg,int l,int r,int k){ if(l==r) return b[l]; int sum=t[t[u].l].sum+t[t[v].l].sum-t[t[og].l].sum-t[t[fg].l].sum; int mid=(l+r)>>1; if(k<=sum) return Answer(t[u].l,t[v].l,t[og].l,t[fg].l,l,mid,k); return Answer(t[u].r,t[v].r,t[og].r,t[fg].r,mid+1,r,k-sum); } void work(){ lg[0]=-1; T=read(); n=read();m=read();kk=read(); fo(i,1,n) b[i]=a[i]=read(),lg[i]=lg[i>>1]+1,col[i]=i; sort(b+1,b+1+n); tot=unique(b+1,b+1+n)-b-1; fo(i,1,n){ a[i]=lower_bound(b+1,b+1+tot,a[i])-b; } fo(i,1,m){ int x=read(),y=read(); add(x,y); add(y,x); } } int main(){ work(); fo(i,1,n){ if(col[i]==i) dfs(i,0,i); } int last=0; char ch[5]; int x,y,k; for(int i=1;i<=kk;i++){ scanf("%s",ch);x=read()^last;y=read()^last; if(ch[0]==\'Q\'){ k=read()^last; int og=lca(x,y),fg=f[og][0]; last=Answer(root[x],root[y],root[og],root[fg],1,tot,k); printf("%d\\n",last); } else{ add(x,y);add(y,x); int fx=col[x],fy=col[y]; if(size[fy]<size[fx]) dfs(y,x,fx); else dfs(x,y,fy); } } return 0; }
以上是关于Luogu 3302 森林(树上维护主席树)的主要内容,如果未能解决你的问题,请参考以下文章