hdu3038 How Many Answers Are Wrong

每个信息给一个子区间[l,r]的和,问有多少信息是错误的。

子区间[l,r]的和可以知道是由r的前缀和减去l-1的前缀和。

所以presum[r]-presum[l-1]=sum[l,r]。所有可以把每个数字当成一个节点,两个节点间的势差为sum。

用并查集维护联通块及所有点与根节点的势差,那么如果两个节点在同一棵树中但是其相对势差和sum不想等这条消息就是假的。

如果两个节点不在一棵树中,合并这两棵树,利用所给节点的势差以及所给节点与各自根节点的势差可以推出根节点间的势差。

find的时候压缩路径并更新字节点到根的势差。

 

 

#include <bits/stdc++.h>
#define pb push_back
#define mp make_pair
#define x first
#define y second
#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define up rt,rt<<1,rt<<1|1
#define mem(x) memset(x,0,sizeof(x))
#define mem1(x) memset(x,-1,sizeof(x))
#define LMissher
using namespace std;
typedef long long ll;
typedef double db;
const int M = 2e5+7;
const double pi = acos(-1);
const int inf = 2147483647;
const int mod = 1e9+7;

int n,q,ans;
int f[M],cnt[M];

void init(){
    for(int i=0;i<=n;i++) f[i]=i,cnt[i]=0;//cnt只需要全部一样,因为只是差值
    ans=0;
}
int find(int x){
    if(x==f[x]) return x;
    int tmp=f[x];
    f[x]=find(f[x]);
    cnt[x]+=cnt[tmp];
    return f[x];
}
int main(){
    #ifdef LMissher
        freopen("1.in","r",stdin);
        freopen("1.out","w",stdout);
    #endif
    while(~scanf("%d%d",&n,&q)){
        init();
        while(q--){
            int l,r,sum;
            scanf("%d%d%d",&l,&r,&sum);l-=1;//r与l-1的区间和为sum,也就是说s[r]=s[l-1]+sum,r由l-1+sum转化而来
            int fx=find(l),fy=find(r);
            if(fx==fy){//这两个数字在一棵树里
                if(cnt[r]-cnt[l]!=sum) ans++;//差值不为sum
            }
            else{//不在一棵树里直接合并
                cnt[fy]=cnt[l]-cnt[r]+sum;//根节点的差值可有已知的l与r节点的差值转化而来
                //r与l分别在根节点下方,且差值为cnt[r]与cnt[l](r、l比根节点值大)
                f[fy]=fx;
            }
        }
        printf("%d\n",ans);
    }
    return 0;
}
View Code

 

转载于:https://www.cnblogs.com/LMissher/p/9627558.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值