并查集-解决区间和纠错问题 hdu-3038
题目:多次给出信息,告诉你[a,b]区间的和,求多少个错误信息(错误信息不考虑)。
乍一看有点像线段树,但想想就发现这个并不能用线段树方便地解决。后来经提醒是并查集的一种经典题型。
把区间抽象为并查集的子节点和母根结点,子节点存放了到根节点的区间和。这样当引入一个新的区间,如果区间左右界根节点不同就一定不存在矛盾(有点种类并查集的意思,形象来看就是存在冗余区间用于调整),然后可以通过现存集合推导出子节点到根节点的区间和。如果根节点相同则要判断一下是否矛盾(画个图对线段加加减减就能推出公式了,文字不太好描述)。
这里注意一下数字是存在于端点上的,所以为了便于模拟,将小节点值--,或者将大节点++(注意不要溢出哦)。
#include <iostream> #include <cstdio> #define LL long long int using namespace std; int pre[200005]; LL val[200005]; int Find(int x) { if(pre[x]==x) return x; int te=Find(pre[x]); val[x]+=val[pre[x]]; return pre[x]=te; } void ini() { int lx=200000; for(int i=0;i<=lx;i++) pre[i]=i,val[i]=0; } int main() { cin.sync_with_stdio(false); int n,m; while(cin>>n>>m) { ini(); int u,v,w,ans=0; for(int i=0;i<m;i++) { cin>>u>>v>>w; u--; int t[2]={Find(u),Find(v)}; if(t[0]==t[1]) { if(val[v]-val[u]!=w) ans++; } else { pre[t[1]]=t[0]; val[t[1]]=val[u]-val[v]+w; } } cout<<ans<<endl; } return 0; }