这道题我拖了有8个月...
今天放假拉出来研究一下带权的正确性,还有半开半闭的处理还有ab指向的一系列细节问题
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
using namespace std;
const int maxn = 200010;
int p[maxn],r[maxn];
void init(int n){
memset(r,0,sizeof r);
for(int i=0;i<=n+2;i++)p[i]=i;
}
int find(int x){
if(x==p[x]) return x;
int oldp=p[x];
int t=find(p[x]);
r[x]+=r[oldp];
return p[x]=t;
}
void link(int fa,int fb,int a,int b,int c){
p[fb]=fa;
r[fb]=r[a]-r[b]+c;
}
int main(){
int n,m;
while(cin>>n>>m){
init(n);
int ans=0;
for(int i=1;i<=m;i++){
int a,b,c; scanf("%d%d%d",&a,&b,&c);
if(a>b)swap(a,b); a--;//反例: 仅一边 4 3 100 WA
int fa=find(a),fb=find(b);
if(fa==fb){
if(r[b]-r[a]!=c)ans++;
}else{
link(fa,fb,a,b,c);
}
}
// for(int i=1;i<=12;i++) cout<<"p["<<i<<"]="<<p[i]<<" "<<"r["<<i<<"]="<<r[i]<<endl;
printf("%d\n",ans);
}
return 0;
}
/*样例
100 3
1 3 24
5 10 30
3 10 60
*/
//如果父节点比子节点id大,那子节点的秩为负值也是没关系的(要是正就说明中间和为负值)
//4 10 30
//2 10 60 子节点比父节点大,正ok
//4 10 30
//5 10 60 子节点比父节点小,负ok
//另外有一点是b总是指向a(前面看出了ab总是单调的),所以用矢量求r[fb]总是利用r[a]+w=r[b]+r[fb] (不是-w)
//关于半闭半开还没有很好的领会(除了相等ab的合法处理以外),可能所有式子存在偏移那就不会影响整体的正确性?(只要确保a<=b的前提下使用),
//有点小疑问是这样会不会影响单一区间的正确结果?没有可视化做数据来测试真痛苦不做了