How Many Answers Are Wrong 【HDU
阿新 • • 發佈:2018-12-11
題目連結
思路:
題目讓我們求的是一共N個數的Q次詢問,每次詢問判斷是否是個正確解,如果是個正確,或者不能確定的解,那麼我們就把它當作條件存起來,反之,如果確定它是個錯解,我們就對於最後要輸出的答案+1。
那麼,問題就是怎麼處理錯誤與需要判斷的條件了,這道題一開始的不理解在於如果一個區間確定,但是現在詢問它的一個真子集區間,且真子集空間比父區間大怎麼辦?沒有關係,題目並沒有說明區間一定是個正數,所以可以負數,那麼這道題就可以解了。
這就是一個並查集的思維了,我們將一個區間【a,b】看作並查集的兩個需要連結的點,但是這樣會發現一件事,就是用到種類並查集的時候,我們求從根節點到目前節點的字首和 ,值就會少去a點的值,所以,我處理的是【a-1,b】。
接下來,就是最繁瑣的連結問題,我令a->b為a節點到b節點的距離,舉個例子,令u==root(a),那麼,sum[a]就是a到其根節點的距離,那麼對於同一棵樹上的節點,我欲求a->b的距離,怎麼求?欲求a->b,已知root(a)->a、root(b)->b,即sum[a],sum[b],又因為它們在同一棵樹上,root(a) == root(b),看作root,向量法來看,就是a->b = -root(a)->a + root(b)->b,也就是說,a到b的距離為sum[b]-sum[a] 。
既然知道了,同一棵樹上該如何處理,我們用同樣的方法處理一下不同樹的情況。已知a、b它們在不同的樹上,已知root(a)->a、root(b)->b,我們想將a的根連在b的根上,即所求解為:root(b)->root(a)。 解:root(b)->root(a) == root(b)->b + b->a - root(a)->a;即sum[root(a)] = sum[b] + det - sum[a]。
完整程式碼:
#include <iostream> #include <cstdio> #include <cmath> #include <string> #include <cstring> #include <algorithm> #include <limits> #include <vector> #include <stack> #include <queue> #include <set> #include <map> #define lowbit(x) ( x&(-x) ) #define pi 3.141592653589793 #define e 2.718281828459045 using namespace std; typedef long long ll; const int maxN=200005; int N, M, ans=0; int root[maxN]; int sum[maxN]; int fid(int x) { if(x==root[x]) return x; int tmp=root[x]; root[x]=fid(root[x]); sum[x]+=sum[tmp]; return root[x]; } void mix(int x, int y, int det) //對於位於前面的數需要“-1”,不然則要特判x點上的值 { int u=fid(x), v=fid(y); if(u==v) { if(sum[x] - sum[y] != det) ans++; } else { root[u]=v; sum[u]=det+sum[y]-sum[x]; } } int main() { while(scanf("%d%d", &N, &M)!=EOF) { ans=0; for(int i=0; i<=N; i++) { root[i]=i; sum[i]=0; } for(int i=1; i<=M; i++) { int e1, e2, e3; scanf("%d%d%d", &e1, &e2, &e3); mix(e1-1, e2, e3); } printf("%d\n", ans); } return 0; }