BZOJ3123:[SDOI2013]森林——题解

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了BZOJ3123:[SDOI2013]森林——题解相关的知识,希望对你有一定的参考价值。

http://www.lydsy.com/JudgeOnline/problem.php?id=3123

https://www.luogu.org/problemnew/show/P3302

树上主席树操作方法看:http://www.cnblogs.com/luyouqi233/p/8159528.html

 (BZOJ2588:Count on a tree

这题要动态树,显然不可能LCT套主席树啊。

那我们完全可以启发式合并一下主席树。

剩下的操作就很简单了。

(然而我debug两个小时才发现我n定义了两个emmmm)

#include<cstdio>
#include<cmath>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
using namespace std;
const int N=8e4+10;
inline int read(){
    int X=0,w=0;char ch=0;
    while(!isdigit(ch)){w|=ch==\'-\';ch=getchar();}
    while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar();
    return w?-X:X;
}
struct tree{
    int l,r,sum;
}tr[N*500];
struct node{
    int to,nxt;
}edge[N*2];
int a[N],b[N],rt[N],pool,n,m;
int dep[N],anc[N][20],son[N];
int cnt,head[N],fa[N],vis[N],tot;
inline void add(int u,int v){
    edge[++cnt].to=v;edge[cnt].nxt=head[u];head[u]=cnt;
}
inline void insert(int y,int &x,int l,int r,int p){
    tr[x=++pool]=tr[y];tr[x].sum++;
    if(l==r)return;
    int mid=(l+r)>>1;
    if(p<=mid)insert(tr[y].l,tr[x].l,l,mid,p);
    else insert(tr[y].r,tr[x].r,mid+1,r,p);
}
inline int query(int nl,int nr,int nm,int nfm,int l,int r,int k){
    if(l==r)return l;
    int delta=tr[tr[nl].l].sum+tr[tr[nr].l].sum-tr[tr[nm].l].sum-tr[tr[nfm].l].sum;
    int mid=(l+r)>>1;
    if(delta>=k)return query(tr[nl].l,tr[nr].l,tr[nm].l,tr[nfm].l,l,mid,k);
    else return query(tr[nl].r,tr[nr].r,tr[nm].r,tr[nfm].r,mid+1,r,k-delta);
}
inline void LSH(){
    sort(b+1,b+m+1);
    m=unique(b+1,b+m+1)-b-1;
    for(int i=1;i<=n;i++){
    a[i]=lower_bound(b+1,b+m+1,a[i])-b;
    }
    return;
}
inline int LCA(int i,int j){
    if(dep[i]<dep[j])swap(i,j);
    for(int k=16;k>=0;k--){
        if(dep[anc[i][k]]>=dep[j])i=anc[i][k];
    }
    if(i==j)return i;
    for(int k=16;k>=0;k--){
        if(anc[i][k]!=anc[j][k])i=anc[i][k],j=anc[j][k];
    }
    return anc[i][0];
}
int find(int x){
    if(fa[x]==x)return x;
    return fa[x]=find(fa[x]);
}
void dfs(int u,int f,int root){
    anc[u][0]=f;
    for(int k=1;k<=16;k++)
    anc[u][k]=anc[anc[u][k-1]][k-1];
    son[root]++;dep[u]=dep[f]+1;fa[u]=root;vis[u]=1;
    insert(rt[f],rt[u],1,m,a[u]);
    for(int i=head[u];i;i=edge[i].nxt){
        int v=edge[i].to;
        if(v!=f)dfs(v,u,root);
    }
    return;
}
int main(){
    read();
    n=read();int e=read(),T=read(),last=0;
    for(int i=1;i<=n;i++)
    a[i]=b[++m]=read(),fa[i]=i;
    LSH();
    for(int i=1;i<=e;i++){
    int x=read(),y=read();
    add(x,y);add(y,x);
    }
    for(int i=1;i<=n;i++)
    if(!vis[i]){
        dfs(i,0,++tot);fa[tot]=tot;
    }
    for(int i=1;i<=T;i++){
    char ch=getchar();
        while(ch!=\'Q\'&&ch!=\'L\')ch=getchar();
    if(ch==\'Q\'){
        int x=read()^last,y=read()^last,k=read()^last;
        int t=LCA(x,y),ft=anc[t][0];
        printf("%d\\n",last=b[query(rt[x],rt[y],rt[t],rt[ft],1,m,k)]);
    }else{
        int x=read()^last,y=read()^last;
        add(x,y);add(y,x);
        int u=find(x),v=find(y);
        if(son[u]<son[v]){
        swap(u,v);
        swap(x,y);
        }
        dfs(y,x,u);
    }
    }
    return 0;
}

+++++++++++++++++++++++++++++++++++++++++++

 +本文作者:luyouqi233。               +

 +欢迎访问我的博客:http://www.cnblogs.com/luyouqi233/+

+++++++++++++++++++++++++++++++++++++++++++

 

以上是关于BZOJ3123:[SDOI2013]森林——题解的主要内容,如果未能解决你的问题,请参考以下文章

BZOJ 3123 SDOI2013 森林

bzoj 3123: [Sdoi2013]森林

bzoj3123: [Sdoi2013]森林

主席树 启发式合并bzoj3123: [Sdoi2013]森林

BZOJ 3123 [Sdoi2013]森林 主席树启发式合并

[bzoj3123] [SDOI2013]森林 主席树+启发式合并+LCT

(c)2006-2024 SYSTEM All Rights Reserved IT常识