並查集-How Many Answers Are Wrong(hdu3038)
阿新 • • 發佈:2018-12-04
題意:
現給出n個數字組成的序列,編號為1~n;
給出m個查詢,每個查詢的答案由a,b,s三個陣列成,表示從第a個數加到第b個數的和為s(對於a~b之間的和是s,其實可以理解成b比a-1大s);
但是其中有一些是有矛盾的(或者說錯誤的),求錯誤的查詢答案有多少個。
題解:
經典的帶權並查集問題;
1.sum[x]表示x-1到f[x]的和
2.sum[x] = sum[x]+sum[f[x]];//find_head()
3.並查集聯合父節點不同sum[fb] = s+sum[a]-sum[b];
4.並查集聯合父節點相同if(sum[b]-sum[a]) != s) return true;
#include <iostream> #include <cstdio> #include <cstring> using namespace std; const int N = 200005; int f[200005]; int sum[200005]; int find_head(int x) { int fx = x; if(x != f[x]) { fx = find_head(f[x]); sum[x] = sum[x]+sum[f[x]]; f[x] = fx; } return fx; } bool union_set(int a, int b, int s)//假話return true { int fa = find_head(a); int fb = find_head(b); if(fa != fb) { f[fb] = fa; sum[fb] = s+sum[a]-sum[b]; return false; } if((sum[b]-sum[a]) != s) return true; return false; } int main() { int n, m; while(scanf("%d%d",&n,&m) == 2) { int ans = 0; memset(sum, 0, sizeof(sum)); for(int i = 0; i <= n; i++) { f[i] = i; } while(m--) { int a, b, s; scanf("%d%d%d", &a,&b,&s); a--; //對於a~b之間的和是s,其實可以理解成b比a-1大s if(union_set(a, b, s)) { ans++; } } cout<<ans<<endl; } return 0; }