洛谷P3224 永无乡 [HNOI2012] 线段树/splay/treap

时间:2023-03-09 17:15:29
洛谷P3224 永无乡 [HNOI2012] 线段树/splay/treap

正解:线段树合并

解题报告:

传送门!

这题也是有很多解法,eg:splay,treap,...

然而我都不会我会学的QAQ!

反正今天就只讲下线段树合并怎么做QAQ

首先看到这样子的说第k重要的是什么,然后又不是问某个区间内,那就肯定是权值线段树做嘛

然后考虑到连桥,那显然就是并茶几维护连通性,然后如果不在一个块的连起来了就线段树合并一下就好了嘛

然后就麻油辣!overr!

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define rg register
#define gc getchar()
#define rp(i,x,y) for(rg int i=x;i<=y;++i) const int N=+;
int n,m,q,st[N],tot,nod_cnt,rt[N],r,l,fa[N],num[N];
struct sgtr{int l,r,ls,rs,sz,name;}tr[N<<]; il int fd(int x){return fa[x]==x?x:fa[x]=fd(fa[x]);}
il int read()
{
rg char ch=gc;rg int x=;rg bool y=;
while(ch!='-' && (ch>'' || ch<''))ch=gc;
if(ch=='-')ch=gc,y=;
while(ch>='' && ch<='')x=(x<<)+(x<<)+(ch^''),ch=gc;
return y?x:-x;
}
il char rdch(){rg char ch=gc;while(ch!='Q' && ch!='B')ch=gc;return ch;}
il int modify(int l,int r,int dat)
{
int nw=++nod_cnt;tr[nw].l=l;tr[nw].r=r;tr[nw].sz++;if(l==r)return nw;int mid=(l+r)>>;
if(dat<=mid)tr[nw].ls=modify(l,mid,dat);
else tr[nw].rs=modify(mid+,r,dat);
return nw;
}
il int merge(int nw1,int nw2)
{
if(!nw1 || !nw2)return nw1+nw2;
if(tr[nw1].l==tr[nw1].r)return tr[nw1].sz+=tr[nw2].sz,nw1;
tr[nw1].sz+=tr[nw2].sz;tr[nw1].ls=merge(tr[nw1].ls,tr[nw2].ls);tr[nw1].rs=merge(tr[nw1].rs,tr[nw2].rs);
return nw1;
}
il int query(int nw,int dat)
{
if(tr[nw].sz<dat)return -;
if(tr[nw].l==tr[nw].r)return num[tr[nw].l];
if(tr[tr[nw].ls].sz>=dat)return query(tr[nw].ls,dat);
return query(tr[nw].rs,dat-tr[tr[nw].ls].sz);
} int main()
{
// freopen("ywx.in","r",stdin);freopen("ywx.out","w",stdout);
n=read();m=read();rp(i,,n){fa[i]=i;int x;num[x=read()]=i,rt[i]=modify(,n,x);}
rp(i,,m){int x=read(),y=read();x=fd(x);y=fd(y);if(x!=y)rt[x]=merge(rt[x],rt[y]),fa[y]=x;}
q=read();
rp(i,,q){char op=rdch();int x=read(),y=read();if(op=='B'){x=fd(x);y=fd(y);if(x!=y)merge(rt[x],rt[y]),fa[y]=x;}else{printf("%d\n",query(rt[fd(x)],y));}}
return ;
}

然后这儿是代码QwQ!