数学上来先打表
题解
我们很容易发现,这种构成连通块的查询元素的题很容易用带权并查集来处理。
由于它第三个操作求的是块中第k小的数,如果一个一个查询肯定不好处理,我们需要一种更加高效的查询方式。
于是,我们就想到了分块,将每个点的导值分块,查询时跳着查,到第k所在的那个块时再一个一个查,这样就可以地进行查询了。
而第二个操作要求对这个进行可持久化。我们发现我们对刚做的一个链接操作进行撤回是十分容易的,于是我们可以把所有的操作建成一棵树,如果是返回操作就接在它返回的操作的点上,否则就接在上一个操作上,我们执行时只需要查询遍历这棵树就可以了。
然后我们便可以用的时间复杂度解决这道题了。虽说这时间复杂度很丑。
源码
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<vector>
#include<queue>
#include<map>
#include<set>
#include<bitset>
#include<stack>
using namespace std;
typedef long long LL;
const int mo=1e9+7;
#define MAXN 100005
const int MAXM=1200;
typedef pair<int,int> pii;
template<typename _T>
void read(_T &x){
_T f=1;x=0;char s=getchar();
while(s>'9'||s<'0'){if(s=='-')f=-1;s=getchar();}
while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+(s^48);s=getchar();}
x*=f;
}
template<typename _T>
_T Fabs(_T x){return x<0?-x:x;}
int n,n1,n2,m,a[MAXN],id[MAXN],c[MAXN];
int fa[MAXN],dis[MAXN],sum[MAXN][MAXN/MAXM+5];
int opt[MAXN],X[MAXN],Y[MAXN],ans[MAXN];
vector<int> vec[MAXN];
bool cmp(int x,int y){return a[x]<a[y];}
void makeSet(int x){for(int i=1;i<=x;i++)fa[i]=i,dis[i]=1;}
int findSet(int x){if(fa[x]==x)return x;return findSet(fa[x]);}
int query(int x,int y){
if(y>dis[x])return 0;
int t=0;while(y>sum[x][t])y-=sum[x][t++];
for(int i=0;i<MAXM;i++){
if(findSet(id[t*MAXM+i])==x)y--;
if(!y)return id[MAXM*t+i];
}
}
void dfs(int x){
//printf("%d:%d\n",x,opt[x]);
if(opt[x]==1){
int u=findSet(X[x]),v=findSet(Y[x]);
if(dis[u]>dis[v])swap(u,v);//puts("a");
if(u!=v){
fa[u]=v;dis[v]+=dis[u];
for(int i=0;i<=n2;i++)sum[v][i]+=sum[u][i];
}
for(int i=0;i<vec[x].size();i++)dfs(vec[x][i]);
if(u!=v){
fa[u]=u;dis[v]-=dis[u];
for(int i=0;i<=n2;i++)sum[v][i]-=sum[u][i];
}
}
else{
if(opt[x]==3)ans[x]=query(findSet(X[x]),Y[x]);
for(int i=0;i<vec[x].size();i++)dfs(vec[x][i]);
}
}
signed main(){
read(n);read(m);a[0]=-1;n2=n/MAXM+1;
for(int i=1;i<=n;i++)read(a[i]),id[i]=i;
sort(id+1,id+n+1,cmp);makeSet(n);
for(int i=1;i<=n;i++)c[i]=a[id[i]],sum[id[i]][i/MAXM]=1;
for(int i=1;i<=m;i++){
read(opt[i]);read(X[i]);
if(opt[i]==2)vec[X[i]].push_back(i);
else read(Y[i]),vec[i-1].push_back(i);
}
dfs(0);for(int i=1;i<=m;i++)if(opt[i]==3)printf("%d\n",a[ans[i]]);
return 0;
}