维护size即可,更像是简单的划分树,不多说了。
感觉算是比较典型的应用了,可是没想出来线段树做,一直尝试着用伸展树水过去,TLE了N发之后才明白毕竟土洋。
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdlib>
#include <cstdio>
#include <queue>
#include <cmath>
#include <stack>
#include <map>
#include <ctime>
#include <iomanip>
#pragma comment(linker, "/STACK:1024000000");
#define EPS (1e-6)
#define LL long long
#define ULL unsigned long long
#define _LL __int64
#define INF 0x3f3f3f3f
#define Mod 6000007
using namespace std;
int fa[200010];
int re[200010];
int num[200010];
int Find(int x)
{
int t = x;
while(x != fa[x])
x = fa[x];
int g;
while(t != fa[t])
g = fa[t],fa[t] = x,t = g;
return x;
}
int st[800010];
void Init(int site,int l,int r)
{
if(l == r)
{
st[site] = num[l];
return ;
}
int mid = (l+r)>>1;
Init(site<<1,l,mid);
Init(site<<1|1,mid+1,r);
st[site] = st[site<<1] + st[site<<1|1];
}
void Updata(int site,int l,int r,int k,int c)
{
if(l == r)
{
st[site] += c;
return ;
}
int mid = (l+r)>>1;
if(k <= mid)
Updata(site<<1,l,mid,k,c);
else
Updata(site<<1|1,mid+1,r,k,c);
st[site] = st[site<<1] + st[site<<1|1];
}
int Query(int site,int l,int r,int k)
{
if(l == r)
return l;
int mid = (l+r)>>1;
if(k <= st[site<<1|1])
return Query(site<<1|1,mid+1,r,k);
return Query(site<<1,l,mid,k-st[site<<1|1]);
}
int main()
{
int n,m,i,u,v,c,k,fu,fv;
scanf("%d %d",&n,&m);
for(i =1; i <= n; ++i)
fa[i] = i,re[i] = 1,num[i] = 0;
num[1] = n;
Init(1,1,n);
while(m--)
{
scanf("%d",&c);
if(c == 1)
{
scanf("%d",&k);
printf("%d\n",Query(1,1,n,k));
}
else
{
scanf("%d %d",&u,&v);
fu = Find(u);
fv = Find(v);
if(fu != fv)
{
Updata(1,1,n,re[fu],-1);
Updata(1,1,n,re[fv],-1);
re[fv] += re[fu];
fa[fu] = fv;
Updata(1,1,n,re[fv],1);
}
}
}
return 0;
}