[SDOI2013]森林

Description
1(3).jpg

Input
第一行包含一个正整数testcase,表示当前测试数据的测试点编号。保证1≤testcase≤20。
第二行包含三个整数N,M,T,分别表示节点数、初始边数、操作数。第三行包含N个非负整数表示 N个节点上的权值。
接下来 M行,每行包含两个整数x和 y,表示初始的时候,点x和点y 之间有一条无向边, 接下来 T行,每行描述一个操作,格式为“Q x y k”或者“L x y ”,其含义见题目描述部分。

Output
对于每一个第一类操作,输出一个非负整数表示答案。

Sample Input
1
8 4 8
1 1 2 2 3 3 4 4
4 7
1 8
2 4
2 1
Q 8 7 3 Q 3 5 1
Q 10 0 0
L 5 4
L 3 2 L 0 7
Q 9 2 5 Q 6 1 6

Sample Output
2
2
1
4
2

HINT
1(4).jpg


其实这题是个暴力。。。

首先考虑没有连边操作,那么就直接令某个点为根,统计4条链的答案即可

如果有加边操作,我们就直接按秩合并,把较小的接到较大的下面,然后将较小的树全部重构

由于每次合并至少会使得树的大小翻倍,因此一个点重构次数不会超过\(O(\log n)\)

至于动态求Lca?暴力更新倍增数组,当然也可以用LCT

/*program from Wolfycz*/
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define inf 0x7f7f7f7f
using namespace std;
typedef long long ll;
typedef unsigned int ui;
typedef unsigned long long ull;
inline char gc(){
    static char buf[1000000],*p1=buf,*p2=buf;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int frd(){
    int x=0,f=1; char ch=gc();
    for (;ch<'0'||ch>'9';ch=gc())   if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=gc()) x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline int read(){
    int x=0,f=1; char ch=getchar();
    if (ch==EOF)    exit(0);
    for (;ch<'0'||ch>'9';ch=getchar())  if (ch=='-')    f=-1;
    for (;ch>='0'&&ch<='9';ch=getchar())    x=(x<<3)+(x<<1)+ch-'0';
    return x*f;
}
inline void print(int x){
    if (x<0)    putchar('-'),x=-x;
    if (x>9)    print(x/10);
    putchar(x%10+'0');
}
const int N=8e4,M=1e7;
struct S1{
    #define ls(x) tree[x][0]
    #define rs(x) tree[x][1]
    #define T(x) (rs(f[x])==x)
    int tree[N+10][2],f[N+10],stack[N+10];
    bool rev[N+10];
    void Add_rev(int x){
        if (!x) return;
        swap(ls(x),rs(x));
        rev[x]^=1;
    }
    void pushdown(int x){
        if (!rev[x])    return;
        Add_rev(ls(x));
        Add_rev(rs(x));
        rev[x]^=1;
    }
    bool isroot(int x){return ls(f[x])!=x&&rs(f[x])!=x;}
    void move(int x){
        int fa=f[x],son=tree[x][T(x)^1];
        tree[x][T(x)^1]=fa;
        tree[fa][T(x)]=son;
        if (son)    f[son]=fa;
        f[x]=f[fa];
        if (!isroot(fa))    tree[f[x]][T(fa)]=x;
        f[fa]=x;
    }
    void splay(int x){
        int top=0; stack[++top]=x;
        for (int i=x;!isroot(i);i=f[i]) stack[++top]=f[i];
        for (int i=top;i;i--)   pushdown(stack[i]);
        while (!isroot(x)){
            if (!isroot(f[x]))  T(x)==T(f[x])?move(f[x]):move(x);
            move(x);
        }
    }
    void Access(int x){
        int last=0;
        while (x){
            splay(x);
            rs(x)=last;
            last=x,x=f[x];
        }
    }
    void make_root(int x){
        Access(x);
        splay(x);
        Add_rev(x);
    }
    void link(int x,int y){
        make_root(x);
        f[x]=y;
    }
    int lca(int x,int y){
        Access(x),splay(x);
        splay(y);
        while (f[y]){
            y=f[y];
            splay(y);
        }
        return y;
    }
    #undef ls
    #undef rs
    #undef T
}LCT;//Link Cut Tree;
int root[N+10];
struct S2{
    int ls[M+10],rs[M+10],cnt[M+10],tot;
    void insert(int &k,int p,int l,int r,int x){
        cnt[k=++tot]=cnt[p]+1;
        ls[k]=ls[p],rs[k]=rs[p];
        if (l==r)   return;
        int mid=(l+r)>>1;
        if (x<=mid) insert(ls[k],ls[p],l,mid,x);
        else    insert(rs[k],rs[p],mid+1,r,x);
    }
    int Query(int k,int p,int w,int v,int l,int r,int x){
        if (l==r)   return l;
        int mid=(l+r)>>1,res=cnt[ls[k]]+cnt[ls[p]]-cnt[ls[w]]-cnt[ls[v]];
        if (x<=res) return Query(ls[k],ls[p],ls[w],ls[v],l,mid,x);
        else    return Query(rs[k],rs[p],rs[w],rs[v],mid+1,r,x-res);
    }
}CT;//Chairman Tree
int pre[(N<<1)+10],now[N+10],child[(N<<1)+10];
int size[N+10],belong[N+10],v[N+10],list[N+10],rt[N+10],f[N+10];
int tot,Time,T;
void join(int x,int y){pre[++tot]=now[x],now[x]=tot,child[tot]=y;}
void insert(int x,int y){join(x,y),join(y,x);}
void dfs(int x,int fa){
    size[belong[x]=Time]++,f[x]=fa;
    CT.insert(root[x],root[fa],1,T,v[x]);
    for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]) if (son!=fa)    dfs(son,x);
}
void rebuild(int x,int fa){
    belong[x]=belong[fa],f[x]=fa;
    CT.insert(root[x],root[fa],1,T,v[x]);
    for (int p=now[x],son=child[p];p;p=pre[p],son=child[p]) if (son!=fa)    rebuild(son,x);
}
int main(){
    read();
    int n=read(),m=read(),q=read();
    for (int i=1;i<=n;i++)  v[i]=list[i]=read();
    sort(list+1,list+1+n);
    T=unique(list+1,list+1+n)-list-1;
    for (int i=1;i<=n;i++)  v[i]=lower_bound(list+1,list+1+T,v[i])-list;
    for (int i=1;i<=m;i++){
        int x=read(),y=read();
        LCT.link(x,y);
        insert(x,y);
    }
    for (int i=1;i<=n;i++)  if (!belong[i]) rt[++Time]=i,dfs(i,0),LCT.make_root(i);
    char s[5]; int Lastans=0;
    for (int i=1;i<=q;i++){
        scanf("%s",s);
        if (s[0]=='L'){
            int x=read()^Lastans,y=read()^Lastans;
            if (size[belong[x]]>size[belong[y]])    swap(x,y);
            LCT.link(x,y),size[belong[y]]+=size[belong[x]];
            insert(x,y),rebuild(x,y);
        }
        if (s[0]=='Q'){
            int x=read()^Lastans,y=read()^Lastans,k=read()^Lastans;
            int lca=LCT.lca(x,y); LCT.make_root(rt[belong[x]]);
            printf("%d\n",Lastans=list[CT.Query(root[x],root[y],root[lca],root[f[lca]],1,T,k)]);
        }
    }
    return 0;
}

转载于:https://www.cnblogs.com/Wolfycz/p/9994259.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值