陕西省集训(并查集)
来源:互联网 发布:淘宝网怎样开店铺 编辑:程序博客网 时间:2024/04/29 12:03
并查集正常的思想就是每次输入的时候找到两个人的祖先,如果不是一个的话,把随便一个并给另一个,然后最后想知道有多少个不联营的区域就是相当于找多少个爸爸是自己的节点;
int findroot(int i)
{
if(fa[i] == i)
return i;
return fa[i] = findroot(fa[i]); //压缩路径,下次在找祖先的时候可以直接跳转几步,某些题不能压缩,比如会改父节点的题
}
int fx = findroot(l);
int fy = findroot(r);
if(fx != fy)
fa[fy] = fx;
A题:
http://acm.split.hdu.edu.cn/showproblem.php?pid=3038
题目大意:
有n次询问,给出a到b区间的总和,问这n次给出的总和中有几次是和前面已近给出的是矛盾的??
思路:
我们对给出的区间a,b做以下操作,a-1,b 这样的话,当区间为1–2 3–4的时候,我们可以把两个区间合并成是区间1—-4。
在更新的时候,数值小的一定是为根节点,如此我们围绕根节点来更新就可,
#include <iostream>#include <cstdio>#include <cstring>int N,M;using namespace std;const int maxn = 200000+10;int fa[maxn],dis[maxn]; //dist是和前面所有数的和,那么l到r的和就是dist【r】-dist【l】;int findroot(int i){ if(fa[i] == i) return i; int tmp = findroot(fa[i]); dis[i] += dis[fa[i]]; return fa[i] = tmp;}int ans = 0;void init(){ while(~scanf("%d%d",&N,&M)){ ans = 0; for(int i = 1 ; i <= N ;i++) fa[i] = i,dis[i] = 0; int l ,r, sum; for(int i = 0 ; i <M ;i++){ scanf("%d%d%d",&l,&r,&sum); l--; int fx = findroot(l); int fy = findroot(r); if(fx != fy){ fa[fy] = fx; dis[fy] = dis[l]-dis[r]+sum; } else if(dis[r]-dis[l] != sum) ans++; } cout << ans<<endl; }}int main(){ init(); // cout <<ans<<endl; return 0;}
B题:
http://acm.split.hdu.edu.cn/showproblem.php?pid=4496
题意:
有个小朋友要炸公路,问每次炸的时候图中还有多少联通块
思路:
所有的边都炸掉之后肯定是n个联通块,那么从后往前,每次相当在一个空的城市里面建工路,这样就可以用并查集很简单的球出来了
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>using namespace std;const int maxn = 10000 +10;const int maxm = 100000 +10;int N,M;int ans [maxm],fa[maxn];int U[maxm],V[maxm];int findroot(int i){ if(fa[i] == i) return i; return fa[i] = findroot(fa[i]);}void Union(int x,int y){ fa[x] = fa[y];}void init(){ for(int i = 0 ; i <=N ;i++) fa[i] = i; for(int i = 1 ; i <= M; i++){ scanf("%d%d",&U[i],&V[i]); }}void sov(){ ans[M] = N; for(int i = M ;i >0 ;i--){ int x = findroot(U[i]); int y = findroot(V[i]); if(x != y){ Union(x,y); ans[i-1] = ans[i] -1; } else ans[i-1] = ans[i]; } for(int i = 1 ; i <= M ;i++) printf("%d\n",ans[i]);}int main(){ while( cin >> N >>M){ init(); sov(); } return 0;}
c题:
http://poj.org/problem?id=1182
题意:
这个恐怖的食物链,a吃b,b吃c,c吃a,给你一些消息,问有多少矛盾
思路:
围成环,dist改成%3就可以了
#include <iostream>#include <cstdio>#include <algorithm>#include <cstring>const int maxn = 50110;//const int maxm = 100010;using namespace std;int fa[maxn],ra[maxn];int N,K;int ans = 0;int findroot(int i){ int tmp = fa[i]; if(i != tmp){ fa[i] = findroot(tmp); ra[i] = (ra[i]+ra[tmp])%3; } return fa[i];}void init(){ scanf("%d%d",&N,&K); for(int i = 1; i <= N ;i++){ fa[i] = i; ra[i] = 0; } int an,X,Y; for(int i = 1; i <= K ;i++){ scanf("%d%d%d",&an,&X,&Y); if(X > N || Y > N){ ans++; continue; } int fx = findroot(X),fy = findroot(Y); if(an == 1){ if(fx == fy && ra[X]!= ra[Y]){ ans++; continue; } else if(fx != fy){ fa[fy] = fx; ra[fy] = (ra[X]+3-ra[Y]) %3; } } if(an == 2){ if(fx == fy &&ra[X] != (ra[Y]+2)%3){ ans++; continue; } if(fx != fy){ fa[fy] = fx; ra[fy] = (ra[X]+3-ra[Y]+1)%3; } } }}int main(){ init(); cout <<ans<<endl; return 0;}
- 陕西省集训(并查集)
- 陕西省集训(数位dp)
- 陕西省集训(单调队列)
- 2016陕西省ACM 热身体B 种类并查集
- 陕西省集训day1(枚举,贪心,二分)
- 陕西省集训day3(搜索上)
- 陕西省集训 day4(搜索下)
- 2017暑假集训 div1 并查集(1)
- 2017暑假集训 div1 并查集(2)
- 亲属关系--并查集训练T1(并查集之老大合并问题)
- 陕西省集训day2(二分,贪心,枚举续)
- 陕西省集训之树形dp
- 陕西省集训之树状数组
- 2017暑期集训 Day 3 搜索与并查集
- sduacm2016级暑假集训 搜索&并查集
- 并查集训练题解(A-E)
- 并查集训练题解(F-J)
- 并查集训练题 宗教信仰
- WebView开启缓存
- Android 最火的快速开发框架XUtils
- P1756 数字反转
- 计算机网络面试题总结
- STM32单片机的IIC硬件编程---查询等待方式
- 陕西省集训(并查集)
- iOS-CALayer的anchorPoint锚点细解
- Exception raised during rendring:android.graphics.drawable.VectorDrawable_Delegate.nCreateTreeFrom
- java基础之反射
- javascript jquery 对字符串处理方法总结
- jks2pfx-java证书转为.net证书
- 【杭电】 2007 ( 平方和与立方和 )
- git 放弃本地修改 强制更新
- vs2010统计代码行数