[loj519]数学上来先打表

建立操作树,即1和3操作时i-1向i连边,2操作中k向i连边,然后dfs一遍

那么当我们走到一个节点,就执行该操作(修改也是操作),退出后取消该操作即可

于是相当于要维护一个东西,支持:1.加边;2.删边;3.询问联通块的第k小

容易想到按秩合并并查集,考虑询问操作:用分块,维护每一个权值块的权值数量(要离散)

然后就可以确定答案所在权值块,再依次枚举里面的权值并判断是否在联通块内即可

 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 #define N 100005
 4 #define K 1000
 5 #define bl(k) ((k-1)/K)
 6 struct ji{
 7     int nex,to;
 8 }edge[N];
 9 vector<int>v[N];
10 int E,n,m,p[N],a[N],x[N],y[N],b[N],head[N],sz[N],fa[N],ans[N],f[N][105];
11 bool cmp(int x,int y){
12     return a[x]<a[y];
13 }
14 void add(int x,int y){
15     edge[E].nex=head[x];
16     edge[E].to=y;
17     head[x]=E++;
18 }
19 int find(int k){
20     if (k==fa[k])return k;
21     return find(fa[k]);
22 }
23 int query(int k){
24     x[k]=find(x[k]);
25     for(int i=0;i<=bl(n);i++)
26         if (y[k]>f[x[k]][i])y[k]-=f[x[k]][i];
27         else
28             for(int j=i*K+1;j<=(i+1)*K;j++)
29                 if ((find(b[j])==x[k])&&(--y[k]==0))return a[b[j]];
30     return -1;
31 }
32 void add(int k){
33     x[k]=find(x[k]);
34     y[k]=find(y[k]);
35     if (x[k]==y[k])return;
36     if (sz[x[k]]>sz[y[k]])swap(x[k],y[k]);
37     fa[x[k]]=y[k];
38     sz[y[k]]+=sz[x[k]];
39     for(int i=0;i<=bl(n);i++)f[y[k]][i]+=f[x[k]][i];
40 }
41 void del(int k){
42     if (x[k]==y[k])return;
43     fa[x[k]]=x[k];
44     sz[y[k]]-=sz[x[k]];
45     for(int i=0;i<=bl(n);i++)f[y[k]][i]-=f[x[k]][i];
46 }
47 void dfs(int k){
48     if (p[k]==1)add(k);
49     if (p[k]==3)ans[k]=query(k);
50     for(int i=head[k];i!=-1;i=edge[i].nex)dfs(edge[i].to);
51     if (p[k]==1)del(k);
52 }
53 int main(){
54     scanf("%d%d",&n,&m);
55     for(int i=1;i<=n;i++)scanf("%d",&a[i]);
56     memset(head,-1,sizeof(head));
57     for(int i=1;i<=n;i++)fa[i]=b[i]=i;
58     sort(b+1,b+n+1,cmp);
59     for(int i=1;i<=n;i++)sz[i]=f[b[i]][bl(i)]=1;
60     for(int i=1;i<=m;i++){
61         scanf("%d%d",&p[i],&x[i]);
62         if (p[i]==2)add(x[i],i);
63         else{
64             scanf("%d",&y[i]);
65             add(i-1,i);
66         }
67     }
68     dfs(0);
69     for(int i=1;i<=m;i++)
70         if (p[i]==3)printf("%d\n",ans[i]);
71 }
View Code
原文地址:https://www.cnblogs.com/PYWBKTDA/p/11453842.html