HDU-3038 How Many Answers Are Wrong (并查集)
题意:
多组数据输入,每组数据对应n(区间范围1~n) , m个区间关系:给出从a 到 b区间的和为 c ,求判断有几个区间和与之前确立的区间和冲突。
思路:
利用并查集对区间的运用:由于集合与区间性质有很多相似性:比如 交∩ 并∪ ,属于关系等,所以对区间属性的操作,也可以转换为集合上来处理
而在普通的并查集处理中,仅仅是将集合合并而没有处理 所带权值的关系,所以就引入上面权值数组sum[] ,带权的并查集。
如果把所有的值都并到同一个的根集合中,那么利用数组sum[i]记录i~根的区间的和,就可以得到在某范围内的区间和sum[k] = sum[i] - sum[j];(i,j的根相同)
在带权并查集合并中 要通过向量(这里是区间关系)在unite合并过程中 将权值合并 (也是多于普通并查集的一部分);
比如此题: 给出某区间 [x,y] 然后又pre[x],pre[y]其在坐标轴上的关系如下 并且给出[x,y]的区间和为s(在这里sum[y]为y到pre[y]的距离:当pre[y]等于1时也就是上面sum[]的表达意义)
y x pre[y] pre[x] 1 0
<-----------------------------------------
那么 sum[pre[y]] = sum[x] - sum[y] + s;即区间(pre[y],pre[x]) = (x,pre[x]) - (y,pre[y]) + (x,y); 这样就把根都并在一起了
完整代码:
#include <iostream> #include <cstdio> #define rep(i,n,m) for(int i=n;i<m;i++) const int maxn = 2*1e5+10; int pre[maxn]; int sum[maxn];//表示从1-n的区间和,求其他就利用相减组合 int n,m,ans; int find(int x){ if(x != pre[x]){ int root = find(pre[x]); sum[x] +=sum[pre[x]];//路径压缩权值合并 return pre[x] = root; } else return pre[x]; } void unite(int x,int y ,int s){ int fx,fy; fx = find(x); fy = find(y); if(fx!=fy){ pre[fy] = fx; sum[fy] = sum[x] - sum[y] + s; } else if(sum[y] - sum[x]!= s) ans++; } int main(){ while(~scanf("%d%d",&n,&m)){ ans = 0; rep(i,0,n+1) { pre[i] = i; sum[i] = 0; } int x,y,s; while(m--){ scanf("%d%d%d",&x,&y,&s); x--;//x减一后[1,5][6,10]则可以合并 unite(x,y,s); } printf("%d\n",ans); } return 0; }