【并查集】BZOJ4668-冷战

【题目大意】

给出N个军工厂和M 个操作,操作分为两类:

• 0 u v,这次操作苏联会修建一条连接 u 号军工厂及 v 号军工厂的铁路,注意铁路都是双向的;

• 1 u v, Reddington 需要知道 u 号军工厂及 v 号军工厂最早在加入第几条条铁路后会联通,假如到这次操作都没有联通,则输出 0。

【思路】

一开始看到过去状态第一反应可持久化,随即觉得自己简直蠢。

普通的并查集,每次还要记录下t[u],t[u]表示u号军工厂和它的父亲是什么时候连接上的。那么对于u和v,如果它们连通,那么就是u->lca(u,v)->v这条路径上t[u]的最大值。

【错误点】

我居然一开始写了u->fa[u]->v…其实lca就可以了啦,lca不一定是最终的父亲。

  1 #include<iostream>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 const int MAXN=500000+50;
  7 int u[MAXN],h[MAXN],t[MAXN];
  8 int dep[MAXN];
  9 int tim;
 10 int ans=0,preans=0,n,m;
 11
 12 int find(int x)
 13 {
 14     while (x!=u[x])    x=u[x];
 15     return x;
 16 }
 17
 18 void getdep(int x)
 19 {
 20     if (u[x]==x)
 21     {
 22         dep[x]=0;
 23         return;
 24     }
 25     else getdep(u[x]);
 26     dep[x]=dep[u[x]]+1;
 27 }
 28
 29 int ask(int x,int y)
 30 {
 31     int ret=-1;
 32     getdep(x);
 33     getdep(y);
 34     if (dep[x]<dep[y]) swap(x,y);
 35     while (dep[x]>dep[y])
 36     {
 37         ret=max(ret,t[x]);
 38         x=u[x];
 39     }
 40     while (x!=y)
 41     {
 42         ret=max(ret,max(t[x],t[y]));
 43         x=u[x];
 44         y=u[y];
 45     }
 46     return ret;
 47 }
 48
 49 void mintime(int a,int b)
 50 {
 51     int fa=find(a),fb=find(b);
 52     if (fa!=fb) ans=0;
 53         else ans=ask(a,b);
 54     printf("%d\n",ans);
 55     preans=ans;
 56 }
 57
 58 void union_set(int a,int b)
 59 {
 60     ++tim;
 61     int fa=find(a),fb=find(b);
 62     if (fa!=fb)
 63     {
 64         if (h[fa]>h[fb])
 65         {
 66             t[fb]=tim;
 67             u[fb]=fa;
 68         }
 69         else
 70         {
 71             t[fa]=tim;
 72             u[fa]=fb;
 73             if (h[fa]==h[fb]) ++h[fb];
 74         }
 75     }
 76 }
 77
 78 void init()
 79 {
 80     memset(dep,0,sizeof(dep));
 81     for (int i=1;i<=n;i++)
 82         u[i]=i,h[i]=1;
 83 }
 84
 85 void solve()
 86 {
 87     scanf("%d%d",&n,&m);
 88     tim=0;
 89     init();
 90     for (int i=0;i<m;i++)
 91     {
 92         int op,a,b;
 93         scanf("%d%d%d",&op,&a,&b);
 94         a^=preans;
 95         b^=preans;
 96         if (!op) union_set(a,b);
 97             else mintime(a,b);
 98     }
 99 }
100
101 int main()
102 {
103     solve();
104     return 0;
105 }
时间: 2024-08-12 12:41:10

【并查集】BZOJ4668-冷战的相关文章

【BZOJ-4668】冷战 并查集 + 启发式合并 + 乱搞

4668: 冷战 Time Limit: 10 Sec  Memory Limit: 256 MBSubmit: 37  Solved: 24[Submit][Status][Discuss] Description 1946 年 3 月 5 日,英国前首相温斯顿·丘吉尔在美国富尔顿发表“铁幕演说”,正式拉开了冷战序幕. 美国和苏联同为世界上的“超级大国”,为了争夺世界霸权,两国及其盟国展开了数十年的斗争.在这段时期,虽然分歧和冲突严重,但双方都尽力避免世界范围的大规模战争(第三次世界大战)爆发

bzoj4668: 冷战 并查集

并查集,按秩合并,树高log,暴力查询. 果然bzoj新挂的题中过的人多的全是sb题. 写了一发秒WA,发现姿势不对.(@[email protected]) 然后过了50min,开始怀疑人生.(*_*) 这么长时间我lct都写完了.(Q_Q) 本着凡事要往好处想的精神,至少我改正了姿势.(T_T) #include<cstdio> #define N 500005 int n,m,q,k,s,t,l; int f[N],d[N],r[N],p[N]; int find(int i){ if(

[HDU 3712] Fiolki (带边权并查集+启发式合并)

[HDU 3712] Fiolki (带边权并查集+启发式合并) 题面 化学家吉丽想要配置一种神奇的药水来拯救世界. 吉丽有n种不同的液体物质,和n个药瓶(均从1到n编号).初始时,第i个瓶内装着g[i]克的第i种物质.吉丽需要执行一定的步骤来配置药水,第i个步骤是将第a[i]个瓶子内的所有液体倒入第b[i]个瓶子,此后第a[i]个瓶子不会再被用到.瓶子的容量可以视作是无限的. 吉丽知道某几对液体物质在一起时会发生反应产生沉淀,具体反应是1克c[i]物质和1克d[i]物质生成2克沉淀,一直进行直

CodeForces 745C Hongcow Builds A Nation 并查集

题意: 给了你n个城市 m条边 k个政府 每个政府管辖的区域内不能和其他政府的区域有相连 即政府之间不存在路径 问你在维护这种关系的同时 最多再加多少条边 思路: 先找出来每个联通块 再找出来没有归属的孤立的点 把他们都放到最大的联通块里 然后每个联通块之间的点两两连边是n*(n-1)/2条边 最后算出来的ans-m就好了 (看别人的博客学了一个max_element 1 #include<bits/stdc++.h> 2 #define cl(a,b) memset(a,b,sizeof(a

并查集(个人模版)

并查集: 1 int find(int a) 2 { 3 int r=a; 4 while(f[r]!=r) 5 r=f[r]; 6 int i=a; 7 int j; 8 while(i!=r) 9 { 10 j=f[i]; 11 f[i]=r; 12 i=j; 13 } 14 return r; 15 } 16 int merge(int a,int b) 17 { 18 int A,B; 19 A=find(a); 20 B=find(b); 21 if(A!=B) 22 { 23 f[B

并查集应用

题目描述: One way that the police finds the head of a gang is to check people's phone calls. If there is a phone call between A and B, we say that A and B is related. The weight of a relation is defined to be the total time length of all the phone calls

【bzoj3674】 可持久化并查集加强版

http://www.lydsy.com/JudgeOnline/problem.php?id=3674 (题目链接) 题意 维护并查集3个操作:合并:回到完成第k个操作后的状态:查询. Solution 其实就是用主席树的叶子节点维护并查集的可持久化数组fa[]. 细节 终于认识到了按秩合并的强大,单纯写个路径压缩Re飞,写了路径压缩+按秩合并比单纯的按秩合并每快多少→_→ 代码 // bzoj3674 #include<algorithm> #include<iostream>

BZOJ1015[JSOI2008]星球大战starwar[并查集]

1015: [JSOI2008]星球大战starwar Time Limit: 3 Sec  Memory Limit: 162 MBSubmit: 5253  Solved: 2395[Submit][Status][Discuss] Description 很久以前,在一个遥远的星系,一个黑暗的帝国靠着它的超级武器统治者整个星系.某一天,凭着一个偶然的机遇,一支反抗军摧毁了帝国的超级武器,并攻下了星系中几乎所有的星球.这些星球通过特殊的以太隧道互相直接或间接地连接. 但好景不长,很快帝国又重

HDU 5606 tree 并查集

tree 把每条边权是1的边断开,发现每个点离他最近的点个数就是他所在的连通块大小. 开一个并查集,每次读到边权是0的边就合并.最后Ans?i??=size[findset(i)],size表示每个并查集根的size Ans_i=size[findset(i)],sizeAns?i??=size[findset(i)],size表示每个并查集根的sizesize. #include<cstdio> #include<cstring> #include<algorithm>

HDU 5441 离线处理 + 并查集

题意:给n个节点m条带权值边的无向图.然后q个问题,每次询问点对的数目,点对需要满足的条件是:1)连通:2)其路径的最大权值不能超过询问值. 分析:如果没次询问一次,dfs一次,很可能超时,因此可以用并查集.离线处理,把边按权值排序,把问题按大小排序.然后离线的过程就是不断向图中加边的过程. 比如样例如下: 然后离线处理,排完序后将会是一条一条的加边:问题也排了序,因此是个累加过程... 1 #include <cstdio> 2 #include <iostream> 3 #in