zoukankan      html  css  js  c++  java
  • HDU-3038 How Many Answers Are Wrong(带权并查集区间合并)

    http://acm.hdu.edu.cn/showproblem.php?pid=3038

    大致题意:

    有一个区间[0,n],然后会给出你m个区间和,每次给出a,b,v,表示区间[a,b]的区间和为v,但每次给出的区间可能与之前的有冲突,问这样起冲突的区间共有多少个

    首先区间[a,b]的和可由区间[0,b]的和减去区间[0,a-1]的和得到

    但是我们不太可能知道[0,b],故我们只用知道和b的合并过的区间的左端点就行


    其实并查集实质就是一颗树,我们可以以树的角度去看待它,理解维护过程

    不理解的同学可以在纸上多划几遍,理解过程

     1 #include <stdio.h>
     2 #include <string.h>
     3 #include <iostream>
     4 #include <string>
     5 #include <math.h>
     6 #include <algorithm>
     7 #include <vector>
     8 #include <stack>
     9 #include <queue>
    10 #include <set>
    11 #include <map>
    12 #include <sstream>
    13 const int INF=0x3f3f3f3f;
    14 typedef long long LL;
    15 const int mod=1e9+7;
    16 const int maxn=1e5+10;
    17 using namespace std;
    18 
    19 int fa[200005];//fa[i] 存i的最左端点
    20 int sum[200005];//记录i到根节点之间和的差值,若再跟节点右侧 则为负数
    21 
    22 void init(int n)
    23 {
    24     for(int i=0;i<=n;i++)
    25         fa[i]=i;
    26 }
    27 int Find(int x)//带权并查集,此时find不单有查找任务,还有更新距离任务
    28 {
    29     if(x!=fa[x])
    30     {
    31         int t=fa[x];//记录之前的父节点
    32         fa[x]=Find(fa[x]);//路径压缩 
    33         sum[x]+=sum[t];//递归维护sum
    34     }//记录到根节点的距离,根节点是一个区间的一个端点而不是一个区间,输入的区间被合并成了两个点
    35     return fa[x];
    36 }
    37 
    38 int main()
    39 {
    40     #ifdef DEBUG
    41     freopen("sample.txt","r",stdin);
    42     #endif
    43 //    ios_base::sync_with_stdio(false);
    44 //    cin.tie(NULL);
    45     
    46     int n,m;
    47     while(~scanf("%d %d",&n,&m)) 
    48     {
    49         init(n);
    50         memset(sum,0,sizeof(sum));
    51         int ans=0;
    52         for(int i=1;i<=m;i++)
    53         {
    54             int l,r,v;
    55             scanf("%d %d %d",&l,&r,&v);//
    56             int x=Find(l-1); //注意为什么要-1
    57             int y=Find(r);
    58             if(x!=y)//如果不是一个集合 合并 
    59             {
    60                 fa[y]=x;
    61                 sum[y]=sum[l-1]-sum[r]+v;
    62             }
    63             else if(sum[r]-sum[l-1]!=v) ans++;//当有相同的最左端时,直接判断
    64         }
    65         printf("%d
    ",ans);
    66     }
    67     
    68     return 0;
    69 }

    -

  • 相关阅读:
    买卖股票的最佳时机
    删除排序数组中的重复数字
    软件工程第五次作业:个人总结
    软件工程第二次作业——结对编程
    第一次软件工程作业补充plus
    第二次(四则运算,)
    我的第一次
    软件工程--个人总结
    软件工程第二次作业—结对编程
    软件工程第一次作业补充
  • 原文地址:https://www.cnblogs.com/jiamian/p/12256619.html
Copyright © 2011-2022 走看看