28 07 2020

这题折腾了两天了快(再也不想写数据结构了呜呜呜呜呜
这题大概就是在建任意一座桥对每一个点建动态开点权值线段树,联通性可以考虑使用并查集维护,对每个联通块的父亲维护一棵线段树,其余非父亲节点的线段树都可以删掉(节约空间。每次将两个联通块合并(即两个联通块建一座桥)也就是将两颗权值线段树进行合并操作。然后查询即查询当前联通块的第k大,随便查一下就可以了。(要注意空间问题,我卡了一下空间才勉强通过emmm

#include<iostream>
#include<cstring>
#include<cstdio>
#define maxn 100010
#define N 100000
#define mid ((l+r)>>1)
using namespace std;
int fa[maxn],n,m,s[maxn];
struct segtree{
    segtree *so[2];
    int sum;
    segtree(){
        so[0]=so[1]=NULL;
        sum=0;
    }
    void add(int l,int r,int v){
        if(l==r){
            sum++;
            return;
        }
        bool b=v>mid;
        if(b) l=mid+1;else r=mid;
        if(so[b]==NULL) so[b]=new segtree();
        so[b]->add(l,r,v);
        if(so[0]!=NULL)
            sum+=so[0]->sum;
        if(so[1]!=NULL)
            sum+=so[1]->sum;
    }
    int kth(int k,int l,int r){
        if(sum<k)return -1;
        int n=-1;
        if(l==r) {return sum==0?-1:s[l];}
        if(so[0]!=NULL&&so[0]->sum>=k) n=so[0]->kth(k,l,mid);
        else if(so[1]!=NULL){
            if(so[0]!=NULL)
                 n=so[1]->kth(k-so[0]->sum,mid+1,r);
            else n=so[1]->kth(k,mid+1,r);
        }
        return n;
    }
}*root[maxn];
segtree* merge_segtree(int l,int r,segtree *a,segtree *b){
    if(a==NULL)return b;
    if(b==NULL)return a;
    segtree *c=new segtree;
    c->sum=a->sum+b->sum;
    if(l==r)return c;
    c->so[0]=merge_segtree(l,mid,a->so[0],b->so[0]);
    c->so[1]=merge_segtree(mid+1,r,a->so[1],b->so[1]);
    return c;
}
int findfa(int x){
    if(x!=fa[x]){
        delete root[x];
        fa[x]=findfa(fa[x]);
    }
    return fa[x];
}
void prerun(){
    int a;
    for(int i=1;i<=n;i++){
        fa[i]=i;
        root[i]=new segtree;
        scanf("%d",&a);
        s[a]=i;
        root[i]->add(0,N,a);
    }
}
void unity(int x,int y){
    x=findfa(x);
    y=findfa(y);
    if(x!=y){
        fa[x]=y;
        root[y]=merge_segtree(0,N,root[x],root[y]);
        delete root[x];
        root[x]=NULL;
    }
}
int q,x,y;
char tmp[3];
int main(){
    scanf("%d%d",&n,&m);
    prerun();
    for(int i=1;i<=m;i++){
        scanf("%d%d",&x,&y);
        unity(x,y);
    }
    scanf("%d",&q);
    for(int i=1;i<=q;i++){
        scanf("%s%d%d",tmp,&x,&y);
        if(tmp[0]=='Q')
             printf("%d\n",root[findfa(x)]->kth(y,0,N));
        else unity(x,y);
    }
    return 0;
}
延伸阅读
  1. Burnside引理和polya定理
  2. [LuoguP3834]主席树模板题 静态区间K大
  3. [LuoguP4551]最长异或路径
  4. [LuoguP2580]于是他错误的点名开始了
  5. [LuoguP3950] 部落冲突
  6. [BJOI2016] 回转寿司
  7. [Codeforces 547B] Mike and Feet
  8. 午夜杂谈
更多阅读
  1. 上一篇:[BJOI2016] 回转寿司
  2. 下一篇:[LuoguP3950] 部落冲突
发表评论 抢沙发