【洛谷5610】[Ynoi2013] 大學(並查集)
阿新 • • 發佈:2020-08-19
這道題其實和P4462幾乎一樣,但是我卻多調了30min,細節很多。洛谷資料太水了QwQ
\(\large\texttt{Meaning}\)
給定 \(n,m,k\) ,共 \(m\) 個詢問,每次詢問一個區間,問區間內有多少個子區間的異或和等於 \(k\)。
\(\large\texttt{Solution}\)
題目中說是區間,則可以轉化為字首和的形式。
令 \(S_i=a_1~\texttt{xor}~a_2~\texttt{xor}~...~\texttt{xor}~a_i\)
則 \(a_l~\texttt{xor}~a_{l+1}~\texttt{xor}~a_{l+2}~...~\texttt{xor}~a_r=S_r~\texttt{xor}~S_{l-1}\)
然後每次詢問就可轉化為在 \([l-1,r]\) 之間有多少個 \(S_i\) 和 \(S_j\) \((i\le j)\) 使得 \(S_i~\texttt{xor}~S_j=k\)
發現這個可以用莫隊離線下來做,因為 \(S_i~\texttt{xor}~S_j=k\) 即 \(S_i~\texttt{xor}~k=S_j\) , \(S_i\) 數量改變,答案也就相應改變了。
幾個要注意的地方,坑點:
-
題目中沒保證 \(k\) 不為 \(0\) , 即統計貢獻的時候要明確,先改貢獻,還是先改個數
-
陣列的上界定為 \(2e6\) 不是 \(1e6\), 我也不知道為啥。
然後處理好細節後,就能過了。
\(\large\texttt{Code}\)
#include <bits/stdc++.h> using namespace std; #define int long long const int N = 2e6; //細節2 inline int read() { register int s = 0; register bool neg = 0; register char c = getchar(); for (; c < '0' || c > '9'; c = getchar()) neg |= (c == '-'); for (; c >= '0' && c <= '9'; s = s * 10 + (c ^ 48), c = getchar()) ; return (neg ? -s : s); } int a, b, c, s[N + 10], bel[N + 10], p[N + 10], ans, Ans[N + 10]; struct node { int l, r, id; bool operator<(const node &t) const { return (bel[l] ^ bel[t.l]) ? bel[l] < bel[t.l] : (bel[l] & 1 ? r < t.r : r > t.r); } } ask[N + 10]; inline void add(int n) { ans += p[(n ^ c)]; //細節1 p[n]++; } inline void del(int n) { p[n]--; //細節1 ans -= p[(n ^ c)]; } signed main() { a = read(); b = read(); c = read(); int k = (int)(sqrt(a)); for (int i = 1; i <= a; i++) bel[i] = (i - 1) / k + 1; for (int i = 1; i <= a; i++) s[i] = (read() ^ s[i - 1]); for (int i = 1; i <= b; i++) { ask[i].l = read() - 1; ask[i].r = read(); ask[i].id = i; } sort(ask + 1, ask + b + 1); // p[0]= 1; int l = 1, r = 0; //其實這裡左端點必須設為1,如果設為0,則要先將0這個位置計數1. for (int i = 1; i <= b; i++) { while (l < ask[i].l) del(s[l++]); while (l > ask[i].l) add(s[--l]); while (r < ask[i].r) add(s[++r]); while (r > ask[i].r) del(s[r--]); Ans[ask[i].id] = ans; } for (int i = 1; i <= b; i++) printf("%lld\n", Ans[i]); return 0; }