您的位置:首页 > 其它

BZOJ 2733 [HNOI2012]永无乡 ——线段树 并查集

2017-04-20 17:14 435 查看

用并查集维护联通块。

用线段树的合并来合并联通块。

自己YY了一个写法。

#include <map>
#include <cmath>
#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
#define D(i,j,k) for (int i=j;i>=k;--i)
#define ll long long
#define mp make_pair
#define maxn 150005

int ls[maxn<<5],rs[maxn<<5],rt[maxn];
int fa[maxn],n,m,tot,sum[maxn<<5],q; char opt[11];

void modify(int o1,int &o2,int l,int r,int x,int f)
{
o2=++tot;sum[o2]=sum[o1]+f;if(l==r)return;int mid=l+r>>1;
if (x<=mid) rs[o2]=rs[o1],modify(ls[o1],ls[o2],l,mid,x,f);
else ls[o2]=ls[o1],modify(rs[o1],rs[o2],mid+1,r,x,f);
}

int gf(int k)
{
if (fa[k]==k) return k;
else return fa[k]=gf(fa[k]);
}

int merge(int o1,int o2,int l,int r)
{
if (!(o1*o2)) return o1+o2;
int mid=l+r>>1;sum[o1]+=sum[o2];
ls[o1]=merge(ls[o1],ls[o2],l,mid);
rs[o1]=merge(rs[o1],rs[o2],mid+1,r);
return o1;
}

int query(int o,int l,int r,int x)
{
if (sum[o]<x) return -1;
if (l==r) return l;
int mid=l+r>>1;
if (x<=sum[ls[o]]) return query(ls[o],l,mid,x);
else return query(rs[o],mid+1,r,x-sum[ls[o]]);
}

void Debug(int o,int l,int r)
{
if (!o) return ;
printf(" %d %d == %d\n",l,r,sum[o]);
if (l==r) return ;
Debug(ls[o],l,l+r>>1);
Debug(rs[o],(l+r>>1)+1,r);
}

int list[maxn];

int main()
{
scanf("%d%d",&n,&m);
F(i,1,n) fa[i]=i,rt[i]=0;
F(i,1,n)
{
int x;
scanf("%d",&x);
modify(rt[i],rt[i],1,n,x,1);
list[x]=i;
}
F(i,1,m)
{
int x,y,fx,fy; scanf("%d%d",&x,&y);
fx=gf(x);fy=gf(y);
if (fx==fy) continue;
else
fa[fy]=fx,rt[fx]=merge(rt[fx],rt[fy],1,n);
}
scanf("%d",&q);
F(i,1,q)
{
int x,y,fx,fy,tmp;
scanf("%s%d%d",opt,&x,&y);
switch(opt[0])
{
case 'Q':
fx=gf(x);
tmp=query(rt[fx],1,n,y);
printf("%d\n",tmp==-1?-1:list[query(rt[fx],1,n,y)]);
break;
case 'B':
fx=gf(x);fy=gf(y);
if (fx!=fy)
{
fa[fy]=fx;
rt[fx]=merge(rt[fx],rt[fy],1,n);
}
break;
}
}
}

  

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: