永无乡「HNOI2012」

题意

每个数有一个排名,要求维护两种操作:

  1. \(x\)\(y\)所在的联通块连载一起。

  2. 查询\(x\)所在联通块的\(k\)小值。


思路

思路显然,并查集维护连通性,动态开点权值线段树合并维护查询。这道题污染了HNOI。

代码

#include <bits/stdc++.h>

using namespace std;

namespace StandardIO {

    template<typename T> inline void read (T &x) {
        x=0;T f=1;char c=getchar();
        for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
        for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
        x*=f;
    }
    template<typename T> inline void write (T x) {
        if (x<0) putchar('-'),x=-x;
        if (x>=10) write(x/10);
        putchar(x%10+'0');
    }

}

using namespace StandardIO;

namespace Solve {
    
    const int N=100001;
    
    int n,m,q;
    int val[N],trn[N];
    int f[N];
    int cnt;
    struct node {
        int lc,rc;
        int l,r,val;
    } tree[N*40];
    int root[N];
    
    inline void pushup (int pos) {
        tree[pos].val=tree[tree[pos].lc].val+tree[tree[pos].rc].val;
    }
    void build (int rt,int l,int r,int &pos) {
        if (!pos) pos=++cnt; 
        tree[pos].l=l,tree[pos].r=r,tree[pos].val=0;
        if (l==r) return tree[pos].val=(l==val[rt]),void();
        int mid=(l+r)>>1;
        if (val[rt]<=mid) build(rt,l,mid,tree[pos].lc);
        else build(rt,mid+1,r,tree[pos].rc);
        pushup(pos);
    }
    int query (int k,int pos) {
        if (tree[pos].l==tree[pos].r) return tree[pos].l;
        if (k<=tree[tree[pos].lc].val) return query(k,tree[pos].lc);
        return query(k-tree[tree[pos].lc].val,tree[pos].rc);
    }
    void Tmerge (int &x,int y) {
        if (!x) return x=y,void();
        if (!y) return;
        if (tree[x].l==tree[x].r) return tree[x].val+=tree[y].val,void();
        Tmerge(tree[x].lc,tree[y].lc),Tmerge(tree[x].rc,tree[y].rc);
        pushup(x);
    }
    inline int find (int x) {
        return (f[x]==x)?x:f[x]=find(f[x]);
    }
    inline void merge (int x,int y) {
        x=find(x),y=find(y);
        if (f[x]!=y) f[x]=y,Tmerge(root[y],root[x]);
    }
    void dfs (int now) {
        cout<<tree[now].l<<' '<<tree[now].r<<endl;
        if (tree[now].lc) cout<<"lc:",dfs(tree[now].lc);
        if (tree[now].rc) cout<<"rc:",dfs(tree[now].rc);
    }

    inline void MAIN () {
        read(n),read(m);
        for (register int i=1; i<=n; ++i) {
            read(val[i]),trn[val[i]]=i,f[i]=i,build(i,1,n,root[i]);
        }
        for (register int i=1; i<=m; ++i) {
            int x,y;
            read(x),read(y);
            merge(x,y);
        }
        read(q);
        while (q--) {
            char op;int x,y;
            cin>>op,read(x),read(y);
            if (op=='B') {
                merge(x,y);
            } else {
                if (tree[root[find(x)]].val<y) write(-1);
                else write(trn[query(y,root[find(x)])]);
                putchar('\n');
            }
        }
    }

}

int main () {
    Solve::MAIN();
}

猜你喜欢

转载自www.cnblogs.com/ilverene/p/11405510.html