239. 奇偶遊戲
阿新 • • 發佈:2020-10-29
題意:給你m個詢問,每一個詢問給出一個區間的左右端點和區間中的1的數量的奇偶性,輸出不出現矛盾的最大的k值,即1~k無矛盾,1~k + 1矛盾。
方法:帶權並查集 + 離散化
設區間左右端點a和b,01序列的字首和陣列為s,那麼[a, b]中的1的個數cnt = s[b] - s[a - 1], 那麼cnt是奇是偶和s[b] - s[a - 1]有關:
- s[b]和s[a - 1]同奇偶,cnt為偶數
- s[b]和s[a - 1]不同奇偶,cnt為奇數
那麼對於輸入的a b odd/even
, 可以將他看成是s[b]和s[a - 1]的奇偶性,如果是a b odd
則s[b]和s[a - 1]的奇偶性不同反之相同, 簡單起見,把s[b]和s[a - 1]的奇偶關係之間看成是點b
這樣就可以通過並查集來維護已經確定奇偶關係的點了。
設點x,d[x]表示點x和它所在樹的根之間的奇偶關係(同0,異1),所以兩個點x和y的奇偶關係應該是,在x和y在同一棵樹中時,它們和根的奇偶關係的異或,即:d[x] ^ d[y]
當x和y不再同一棵樹中時,需要根據題目給出的x和y的奇偶關係來合併x所在的樹和y所在的樹,合併x和y所在的樹的關鍵問題就是得到x所在樹的樹根px和y所在樹的樹根py之間的奇偶關係,這樣在令p[px] = py後,才能進一步得到x所在樹的所有結點和py的奇偶關係。
求x所在樹的樹根px和y所在樹的樹根py之間的奇偶關係:設輸入的x和y的奇偶關係為ans(同奇,同偶為0,否則為1),可以知道在合併完x和y所在的樹後,ans = d[x] ^ d[px] ^ d[y],所以可得:d[px] = d[x] ^ d[y] ^ ans,所以在合併x和y所在的樹時,需要將d[px]賦值為d[x] ^ d[y] ^ ans,表示原本x所在樹的根和y所在樹的根之間的奇偶性關係。
注意:合併x和y所在的樹是在輸入了x和y的奇偶關係,並且x和y不再同一棵樹中才進行的,如果x和y已經在同一棵樹中,那麼就應該對這個query進行檢驗。
#include<iostream> #include<vector> #include<algorithm> using namespace std; const int M = 20010; struct Node{ int l, r; string s; }; int p[M], d[M]; vector<Node> query; int a[M], t; int n, m; int k; int find(int x){ int l = 1, r = k; while(l < r){ int mid = l + r >> 1; if(a[mid] >= x) r = mid; else l = mid + 1; } return l; } int get(int x){ if(p[x] != x){ int root = get(p[x]); d[x] = d[x] ^ d[p[x]]; p[x] = root; } return p[x]; } int merge(int x, int y, int e){ int t = d[x] ^ d[y]; x = get(x), y = get(y); p[x] = y, d[x] = t ^ e; } int main(){ cin >> n >> m; for(int i = 1; i <= m; i ++){ int l, r; string s; cin >> l >> r >> s; a[++ t] = l - 1; // 注意雖然輸入的是 l r s, 但其實給出的是點r和點l - 1的奇偶關係 a[++ t] = r; query.push_back({l - 1, r, s}); } sort(a + 1, a + t + 1); for(int i = 1; i <= t; i ++) if(i == 1 || a[i] != a[k]) a[++ k] = a[i]; for(int i = 1; i <= k; i ++) p[i] = i; int res = 0; for(int i = 0; i < query.size(); i ++){ string s = query[i].s; int u = find(query[i].l), v = find(query[i].r); if(get(u) != get(v)) merge(u, v, s == "odd" ? 1 : 0); else if(s == "even" && d[u] ^ d[v]) break; else if(s == "odd" && d[u] ^ d[v] == 0) break; res ++; } cout << res; return 0; }