[HDU3038] [2009多校聯考13] How Many Answers Are Wrong [帶權並查集]
阿新 • • 發佈:2018-12-12
題意:給出一個長度為的序列。 按順序給出條資訊,每條資訊表示區間的和為。 如果第條資訊和之前已知的資訊衝突,那麼這條資訊是無效的。 求一共有多少條無效資訊。
我們考慮對第條資訊建立一個關係,表示即 這其實是字首和的差值 某一個點可能有很多個點有關係。這些關係不需要一一表示出來 所有和有關係的點顯然可以看作一個集合 就像一顆樹,用一個點作為這個集合的根 那麼我們只需要分別記錄也就是和的關係,就可以表示出現有的所有關係。
假設現在處理到。 和
如果和本來就間接有關係了,那麼 可以利用和來得到和已知的關係 即 顯然,這條資訊是否合法可以根據是否等於來判定。
如果和本來沒有關係,現在它們有關係了,和也有關係了 我們就要把它們關聯起來,比方說建立 更新
以上,建一個帶權並查集就可以解決這道題
值得一提的是本題的區間實際上是離散的點,所以區間要建成左開右閉或者左閉右開
可能這麼講比較容易懂:
類似的例子線上段樹題裡面也有,一個經典的資料就是和這兩個區間
注意路徑壓縮的時候也要更新權值
Code:
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cstring>
#include<cctype>
#include<algorithm>
#include<cmath>
using namespace std;
int N,M;
int fa[200005]={},val[200005]={};
int find(int x)
{
if(x==fa[x])return x;
else
{
int top=find(fa[x]);
val[x]+=val[fa[x]];
return fa[x]=top;
}
}
int main()
{
while(scanf("%d%d",&N,&M)!=EOF)
{
for(int i=0;i<=N;++i)fa[i]=i,val[i]=0;
int Ans=0;
for(int ta,tb,tc,ffa,ffb,i=1;i<=M;++i)
{
scanf("%d%d%d",&ta,&tb,&tc);
--ta;
ffa=find(ta),ffb=find(tb);
if(ffa!=ffb)
{
fa[ffb]=ffa;
val[ffb]=val[ta]-val[tb]+tc;
}
else if(val[tb]-val[ta]!=tc)++Ans;
}
printf("%d\n",Ans);
}
return 0;
}