生活随笔
收集整理的這篇文章主要介紹了
BZOJ 2733 线段树的合并 并查集
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
思路:
1.線段樹合并(nlogn的)
2.splay+啟發式合并
線段樹合并比較好寫
我手懶
//By SiriusRen
using namespace std;
const
int N=
100050;
int n,
m,
q,a[N],f[N],xx,yy,son[N
*50][
2],
tr[N
*50],root[N],cnt,rev[N];
char op[
10];
int find(
int x){
return x==f[
x]?
x:f[
x]=find(f[
x]);}
void push_up(
int x){
tr[
x]=
tr[son[
x][
0]]+
tr[son[
x][
1]];}
void insert(
int &
x,
int l,
int r,
int wei){
if(!
x)
x=++cnt;
if(l==r){
tr[
x]++;
return;}
int mid=(l+r)>>
1;
if(mid<wei)insert(son[
x][
1],mid+
1,r,wei);
else insert(son[
x][
0],l,mid,wei); push_up(
x);
}
int merge(
int x,
int y){
if(!
y||!
x)
return x^
y;son[
x][
0]=merge(son[
x][
0],son[
y][
0]),son[
x][
1]=merge(son[
x][
1],son[
y][
1]);push_up(
x);
return x;
}
int query(
int x,
int l,
int r,
int num){
if(l==r)
return l;
int mid=(l+r)>>
1;
if(
tr[son[
x][
0]]>=num)
return query(son[
x][
0],l,mid,num);
return query(son[
x][
1],mid+
1,r,num-
tr[son[
x][
0]]);
}
void add(){
int fx=find(xx),fy=find(yy);
if(fx!=fy)root[fx]=merge(root[fx],root[fy]),f[fy]=fx;
}
int main(){scanf(
"%d%d",&n,&
m);
for(
int i=
1;i<=n;i++)scanf(
"%d",&a[i]),f[i]=i,insert(root[i],
1,n,a[i]),rev[a[i]]=i;
while(
m--)scanf(
"%d%d",&xx,&yy),add();scanf(
"%d",&
q);
while(
q--){scanf(
"%s%d%d",op,&xx,&yy);
if(op[
0]==
'Q')
printf(
"%d\n",
tr[root[find(xx)]]<yy?-
1:rev[query(root[find(xx)],
1,n,yy)]);
else add();}
}
轉載于:https://www.cnblogs.com/SiriusRen/p/6532046.html
總結
以上是生活随笔為你收集整理的BZOJ 2733 线段树的合并 并查集的全部內容,希望文章能夠幫你解決所遇到的問題。
如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。