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;
}

 

posted @ 2019-07-17 11:27  Tianwell  阅读(156)  评论(0编辑  收藏  举报