loj 519

loj 519

 

 这个题目我是建立一个操作树,根据时间的关系。 合并的过程还是用并查集来实现(按秩合并),然后关于询问,我是这么处理的,对于每个联通块,我建立一个权值分块,即cnt数组 

由于内存限制,所以我权值的块的大小是1200,块数是最多90,每次递归的时候,就增加cnt,递归回来的时候,就减去cnt,这样就在操作树上实现了添加和删除操作。  

注意这里的并查集是不能路径压缩的。 

loj 519
 1 #include<bits/stdc++.h>
 2 using namespace std;  
 3 #define bl(x)  ((x-1)/B+1)  
 4 #define st(x)  ((x-1)*B+1)  
 5 #define ed(x)  min(n,x*B)   
 6 int const N=100000+10; 
 7 int const B=1200;   
 8 int f[N],a[N],b[N],c[N],cnt[N][90],n,m,sum,h[N],sz[N],ans[N];  
 9 struct edge{int to,nt;}e[N];   
10 struct query{int opt,x,y,id;}q[N];  
11 int cmp(int x,int y){return a[x]<a[y];}
12 int gf(int x){return x==f[x]?  x:gf(f[x]); }
13 void add(int a,int b){ e[++sum].to=b;  e[sum].nt=h[a]; h[a]=sum; }
14 int query(int x,int y){
15     int fx=gf(x),k=1;  
16     for(int i=1;i<90;i++,k++)  
17         if(y>cnt[fx][i]) y-=cnt[fx][i];  
18         else break;  
19     if(k==90) return -1;  
20     for(int i=st(k);i<=ed(k);i++) 
21         if(gf(b[i])==fx){
22             if(!--y) { 
23                 return a[b[i]]; 
24             }
25         }
26 }
27 void dfs(int x){
28     int fx,fy;  
29     if(q[x].opt==1){
30         fx=gf(q[x].x);  
31         fy=gf(q[x].y);  
32         if(sz[fx]>sz[fy])  
33             swap(fx,fy);  
34         if(fx!=fy){
35             f[fx]=fy;  
36             for(int i=1;i<90;i++) cnt[fy][i]+=cnt[fx][i];  
37             sz[fy]+=sz[fx];  
38         }
39     }
40     if(q[x].opt==3){
41         ans[q[x].id]=query(q[x].x,q[x].y);  
42     }
43     for(int i=h[x];i;i=e[i].nt)  
44         dfs(e[i].to);  
45     if(q[x].opt==1){
46         if(fx!=fy){
47             f[fx]=fx; 
48             sz[fy]-=sz[fx];  
49             for(int i=1;i<90;i++) cnt[fy][i]-=cnt[fx][i];  
50         }
51     }
52 }
53 int main(){
54     scanf("%d%d",&n,&m);  
55     for(int i=1;i<=n;i++)  
56         scanf("%d",&a[i]);  
57     for(int i=1;i<=n;i++) b[i]=i;  
58     sort(b+1,b+n+1,cmp);  
59     for(int i=1;i<=n;i++) c[b[i]]=i;    
60     for(int i=1;i<=m;i++){
61         int opt,x,y;  
62         scanf("%d%d",&q[i].opt,&q[i].x);  
63         q[i].id=i;  
64         if(q[i].opt==1){
65             scanf("%d",&q[i].y);  
66             add(i-1,i);  
67         }
68         if(q[i].opt==2){
69             add(q[i].x,i); 
70         }
71         if(q[i].opt==3){
72             add(i-1,i);  
73             scanf("%d",&q[i].y);  
74         }
75     }
76     for(int i=1;i<=n;i++) 
77         f[i]=i,sz[i]=1,cnt[i][bl(c[i])]++; 
78     dfs(0);  
79     for(int i=1;i<=m;i++)  
80         if(q[i].opt==3) printf("%d\n",ans[i]); 
81     return 0; 
82 }
View Code

 

上一篇:@atcoder - Japanese Student Championship 2019 Qualification - E@ Card Collector


下一篇:没有switch-case怎么办?