ZOJ 3261 Connections in Galaxy War (逆向+带权并查集)

题意:有N个星球,每个星球有自己的武力值。星球之间有M条无向边,连通的两个点可以相互呼叫支援,前提是对方的武力值要大于自己。当武力值最大的伙伴有多个时,选择编号最小的。有Q次操作,destroy为切断连接两点的边,query为查询某星球能不能向它人呼叫支援。

还是需要离线逆向并查集求解。思路和HDU 4496很相似,但是此处不一定是把所有边都删去,所以需要删边的情况建立出最终的状态。因为N可以到1e4,所以可以用map嵌套map的方式记录过程中被删去的边,最后再根据删除情况建立状态。

在合并时需要维护自己能够申请到的支援的武力最大值,以及其编号。

 1 #include<stdio.h>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<iostream>
 5 #include<cmath>
 6 #include<map>
 7 using namespace std;
 8 typedef long long LL;
 9 const int maxn = 2e4+5;
10 const int INF= 0x3f3f3f3f;
11 struct Edge{
12     int u,v;
13 }E[maxn];
14 struct Query{
15     int op,a,b;
16     LL ans;
17 }p[maxn*3];
18 LL w[maxn];
19 LL dist[maxn];
20 int fa[maxn];
21 int maxid[maxn];
22 inline int Find(int x) {return fa[x]==x ?x: fa[x]=Find(fa[x]);}
23 //void init(int N){ for(int i=0;i<N;++i) fa[i]=i,dist[i]=w[i],maxid[i]=i;}
24 void Union(int a,int b){
25     a = Find(a),b = Find(b);
26     if(a!=b){
27         fa[a] = b;
28         if(dist[b]<dist[a] || dist[b]==dist[a] && maxid[b]>maxid[a]){
29             dist[b]=dist[a];
30             maxid[b]=  maxid[a];
31         }
32     }
33 }
34 
35 map<int,map<int,int> > tag;
36 
37 int main()
38 {
39     #ifndef ONLINE_JUDGE
40          freopen("in.txt","r",stdin);
41          freopen("out.txt","w",stdout);
42     #endif
43     int T,N,M,Q,u,v,tmp,K,cas=1;
44     char op[10];
45     int mk = 0;
46     while(scanf("%d",&N)==1){
47         if(mk) printf("\n");
48         mk = 1;
49         for(int i=0;i<N;++i) {
50             scanf("%lld",&w[i]);
51             fa[i]=maxid[i]=i;
52             dist[i]=w[i];
53         }
54         tag.clear();
55         scanf("%d",&M);
56         for(int i=1;i<=M;++i){
57             scanf("%d%d",&u,&v);
58             E[i].u =u , E[i].v=v;
59         }
60         scanf("%d",&Q);
61         for(int i=1;i<=Q;++i){
62             scanf("%s%d",op,&p[i].a);
63             if(op[0]=='d') {
64                 p[i].op=0;
65                 scanf("%d",&p[i].b);
66                 tag[p[i].a][p[i].b]=tag[p[i].b][p[i].a]=1;                  //被删边的标记
67             }
68             else p[i].op = 1;                       //0删边,1查询
69         }
70         //因为并不是把边全删完,建立最终状态
71         for(int i=1;i<=M;++i){
72              if(tag[E[i].u][E[i].v]) continue;      //这条边不在
73              else Union(E[i].u,E[i].v);
74         }
75 
76         for(int i=Q;i>=1;--i){
77             if(!p[i].op) Union(p[i].a,p[i].b); 
78             else{
79                 u = Find(p[i].a);
80                 if(dist[u]>w[p[i].a]) p[i].ans=maxid[u];
81                 else p[i].ans= -1;
82             }    
83         }
84         for(int i=1;i<=Q;++i){
85             if(p[i].op) printf("%lld\n",p[i].ans);
86         }
87     }
88     return 0;
89 }

猜你喜欢

转载自www.cnblogs.com/xiuwenli/p/9415716.html