ZOJ 3261 Connections in Galaxy War (离线处理+逆向并查集)
2017-06-14 20:52
375 查看
题目链接:
ZOJ 3261
题意:
给你一些点,每个点有一个权值,然后有一些边,相连且无向的。
然后给你一些操作:
query a: 表示查询a相连通的点中权值最高的点的编号,如果存在多个,输出编号最小的那个。
destory a , b :表示删除a,b之间的边。
题解:
逆向并查集。
如果我们直接按照常规的想法,先用并查集把所有通道连起来,然后再删除边。但是这样想,建立边的关系又把边的关系删除,好像很难实现啊。
所以,我们可以按照逆向思维,先离线输入所有的操作,然后把被destory的通道连接起来,然后再最后一个询问往前面操作,当有destroy a,b时就把a,b再Union_set起来,即遇到destroy时,就恢复a到b之间的关系。倒着做就变成裸的并查集了。
简单来说,就是把要求删除的边全部删除,再从后往前处理操作,这样删边操作转化为了添边的操作。
AC代码:
逆向并查集:
与并查集不同,给出一个图中原有的一些边,然后给出操作,操作不是向图中添加边,而是在已有的边上,将边删除。
对于该种情况,需要首先读入所有操作,即离线处理,把要求删除的边全部删除,再按照从后往前的顺序处理操作,这样删边操作转化为了添边的操作。
ZOJ 3261
题意:
给你一些点,每个点有一个权值,然后有一些边,相连且无向的。
然后给你一些操作:
query a: 表示查询a相连通的点中权值最高的点的编号,如果存在多个,输出编号最小的那个。
destory a , b :表示删除a,b之间的边。
题解:
逆向并查集。
如果我们直接按照常规的想法,先用并查集把所有通道连起来,然后再删除边。但是这样想,建立边的关系又把边的关系删除,好像很难实现啊。
所以,我们可以按照逆向思维,先离线输入所有的操作,然后把被destory的通道连接起来,然后再最后一个询问往前面操作,当有destroy a,b时就把a,b再Union_set起来,即遇到destroy时,就恢复a到b之间的关系。倒着做就变成裸的并查集了。
简单来说,就是把要求删除的边全部删除,再从后往前处理操作,这样删边操作转化为了添边的操作。
AC代码:
#include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #include <set> using namespace std; typedef long long ll; int w,num,len; const int N=12345; int Power ; set< pair<int,int> > edge; struct Query { int op; int a,b; int ans; void Set_data(int opp,int aa,int bb) { op=opp; a=aa; b=bb; } }query[50123]; int uset ,mx ; int find_set(int x) { if(uset[x]!=x) { int f=uset[x]; uset[x]=find_set(uset[x]); mx[x]=max(mx[x],mx[f]); } return uset[x]; } void union_set(int x,int y) { int fx=find_set(x); int fy=find_set(y); if(fx==fy) return; if(mx[fy]>mx[fx]||(mx[fx]==mx[fy]&&fx>fy)) uset[fx]=fy; else uset[fy]=fx; } int main() { // ios::sync_with_stdio(false); int n,m,q; int k = 0; while(~scanf("%d",&n)) { if(k++)puts(""); char op[10]; int a,b; edge.clear(); for(int i=0;i<n;i++) scanf("%d",&Power[i]); scanf("%d",&m); for(int i=0;i<m;i++) { scanf("%d%d",&a,&b); if(a>b) swap(a,b); edge.insert(make_pair(a,b)); } //离线处理 scanf("%d",&q); for(int i=0;i<q;i++) { scanf("%s",op); //I'm sb if(op[0]=='q')//query { scanf("%d",&a); query[i].Set_data(1,a,0); } else if(op[0]=='d') //destory { scanf("%d%d",&a,&b); if(a>b)swap(a,b); // WA了一次 edge.erase(make_pair(a,b)); query[i].Set_data(2,a,b); } } for(int i=0;i<n;i++) { uset[i]=i; mx[i]=Power[i]; } set< pair<int,int> >::iterator it; for(it=edge.begin();it!=edge.end();it++) { a=(*it).first; b=(*it).second; union_set(a,b); } for(int i=q-1;i>=0;i--)//倒着操作 { if(query[i].op==1) //query { if(mx[find_set(query[i].a)] > Power[query[i].a]) { query[i].ans=uset[query[i].a]; //find the answer } else { query[i].ans= -1; //can not find the answer } } else if(query[i].op==2)//destory , connect this operation { union_set(query[i].a,query[i].b); } } for(int i=0;i<q;i++) { if(query[i].op==1)//query { printf("%d\n",query[i].ans); } } } return 0; }
逆向并查集:
与并查集不同,给出一个图中原有的一些边,然后给出操作,操作不是向图中添加边,而是在已有的边上,将边删除。
对于该种情况,需要首先读入所有操作,即离线处理,把要求删除的边全部删除,再按照从后往前的顺序处理操作,这样删边操作转化为了添边的操作。
相关文章推荐
- ZOJ 3261 Connections in Galaxy War 【并查集 + 离线逆向处理】好题!!
- ZOJ 3261 Connections in GalaxyWar(并查集:离线处理)
- ZOJ-3261 Connections in Galaxy War 并查集 离线操作
- ZOJ 3261 Connections in Galaxy War(逆向并查集)
- Zoj 3261 Connections in Galaxy War (逆向并查集)
- ZOJ-3261-Connections in Galaxy War [逆向并查集]
- ZOJ 3261 Connections in Galaxy War(逆向处理)
- ZOJ 3261 Connections in Galaxy War(逆向并查集)
- ZOJ 3261 Connections in Galaxy War (并查集)
- [并查集+路径压缩]zoj 3261:Connections in Galaxy War
- ZOJ 3261 Connections in Galaxy War 反向用并查集
- zoj 3261 - Connections in Galaxy War(并查集)
- ZOJ-3261(Connections in Galaxy War)——并查集
- ZOJ 3261 Connections in Galaxy War 并查集
- ZOJ 3261 Connections in Galaxy War【并查集】
- ZOJ 3261 Connections in Galaxy War【并查集】
- zoj 3261 Connections in Galaxy War 删边并查集模板
- ZOJ 3261 Connections in Galaxy War (并查集)
- Zoj 3261 Connections in Galaxy War【逆序并查集】
- ZOJ 3261 - Connections in Galaxy War ,并查集删边