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 森林(树上维护主席树)的主要内容,如果未能解决你的问题,请参考以下文章

Luogu3302 [SDOI2013]森林

「Luogu P3302」[SDOI2013]森林

[SDOI2013]森林(树上主席树)

P3302 [SDOI2013]森林

主席树启发式合并P3302[SDOI2013]森林

P3302 [SDOI2013]森林 主席树+LCA+启发式合并