每个信息给一个子区间[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; }