莫队——三种题型
普通莫隊
P3901 數列找不同
Thinking
一定是用可以用莫隊來寫題,這點是不用質疑的,所以那就簡單了,只需要判斷每次詢問的區間是否滿足r?l+1==numr - l + 1 == numr?l+1==num就行了。
Coding1Coding_1Coding1?
莫隊寫法
#include <bits/stdc++.h> #define mp make_pair #define pb push_backusing namespace std;typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii;const double pi = acos(-1.0); const double eps = 1e-7; const int inf = 0x3f3f3f3f;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x; }const int N = 1e6 + 10;int n, m, a[N], num[N], ans[N], block, sum, k;struct Node {int l, r, id;// bool operator < (const Node & t) const {// return r < t.r;// } }query[N];bool cmp1(Node x, Node y) {return ((x.l / block) == (y.l / block)) ? x.r < y.r : x.l < y.l; }//按照塊排序bool cmp2(Node x, Node y) {return ((x.l / block) != (y.l / block)) ? x.l < y.l : ((x.l / block) & 1) ? x.r < y.r : x.r > y.r; }//按照塊的奇偶排序void add(int x) {num[a[x]]++;if(num[a[x]] == 1) sum++;// sum += 2 * num[a[x]] - 1; }void del(int x) {num[a[x]]--;if(num[a[x]] == 0) sum--;// sum -= 2 * num[a[x]] + 1; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);n = read(), m = read();for(int i = 1; i <= n; i++) a[i] = read();block = sqrt(n);for(int i = 1; i <= m; i++) {query[i].l = read(), query[i].r = read();query[i].id = i;}sort(query + 1, query + 1 + m, cmp2);int l = 0, r = 0;for(int i = 1; i <= m; i++) {while(r > query[i].r) del(r--);while(r < query[i].r) add(++r);while(l < query[i].l) del(l++);while(l > query[i].l) add(--l);ans[query[i].id] = (sum == query[i].r - query[i].l + 1);}for(int i = 1; i <= m; i++)puts(ans[i] ? "Yes" : "No");return 0; }Coding2Coding_2Coding2?
樹狀數組寫法。
#include <bits/stdc++.h> #define mp make_pair #define pb push_backusing namespace std;typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii;const double pi = acos(-1.0); const double eps = 1e-7; const int inf = 0x3f3f3f3f;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x; }const int N = 1e6 + 10;int n, m, a[N], pos[N], tree[N], ans[N];struct Node {int l, r, id;bool operator < (const Node & t) const {return r < t.r;} }query[N];void add(int x, int value) {while(x < N) {tree[x] += value;x += x & (-x);} }int ask(int x) {int ans = 0;while(x) {ans += tree[x];x -= x & (-x);}return ans; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);n = read(), m = read();for(int i = 1; i <= n; i++) a[i] = read();for(int i = 1; i <= m; i++) {query[i].l = read(), query[i].r = read();query[i].id = i;}sort(query + 1, query + 1 + m);int l = 1;for(int i = 1; i <= m; i++) {for(int j = l; j <= query[i].r; j++) {if(pos[a[j]])add(pos[a[j]], -1);pos[a[j]] = j;add(j, 1);}l = query[i].r + 1;ans[query[i].id] = (ask(query[i].r) - ask(query[i].l - 1) == query[i].r - query[i].l + 1);}for(int i = 1; i <= m; i++)puts(ans[i] ? "Yes" : "No");return 0; }D. Tree and Queries
Thinking
利用dfsdfsdfs序的特性,同一顆子樹上的節點會連成一片,所以很好的將一個樹上問題轉換成了區間問題,這個時候就可以用上莫隊來寫了。
Coding
#include <bits/stdc++.h> #define mp make_pair #define pb push_backusing namespace std;typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii;const double pi = acos(-1.0); const double eps = 1e-7; const int inf = 0x3f3f3f3f;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x; }const int N = 1e5 + 10;int head[N], to[N << 1], nex[N << 1], cnt = 1; int a[N], n, m, block, sum[N], ans[N], Ans[N]; int pre[N], suc[N], rk[N], num;struct Node {int l, r, id, minn;Node(int _l = 0, int _r = 0, int _id = 0, int _minn = 0) :l(_l), r(_r), id(_id), minn(_minn) {} }ask[N];bool cmp(Node a, Node b) {return ((a.l / block) != (b.l / block)) ? a.l < b.l : ((a.l / block) & 1) ? a.r < b.r : a.r > b.r; }void add_edge(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++; }void dfs(int rt, int f) {pre[rt] = ++num;rk[num] = rt;for(int i = head[rt]; i; i = nex[i]) {if(to[i] == f) continue;dfs(to[i], rt);}suc[rt] = num; }void add(int x) {Ans[++sum[a[x]]]++; }void del(int x) {Ans[sum[a[x]]--]--; }int main() {// freopen("in.txt", "r", stdin); // freopen("out.txt", "r", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);n = read(), m = read();block = sqrt(n);for(int i = 1; i <= n; i++) a[i] = read();for(int i = 1; i < n; i++) {int x = read(), y = read();add_edge(x, y);add_edge(y, x);}dfs(1, 0);for(int i = 1; i <= m; i++) {int x = read(), y = read();ask[i] = Node(pre[x], suc[x], i, y);}sort(ask + 1, ask + 1 + m, cmp);int l = 0, r = 0;for(int i = 1; i <= m; i++) {while(r < ask[i].r) add(rk[++r]);while(r > ask[i].r) del(rk[r--]);while(l > ask[i].l) add(rk[--l]);while(l < ask[i].l) del(rk[l++]);ans[ask[i].id] = Ans[ask[i].minn];}for(int i = 1; i <= m; i++) printf("%d\n", ans[i]);return 0; }D. Powerful array
Thinking
同樣是一個區間問題,我們考慮用莫隊如何維護。
假設當前數字xxx出現的次數是nnn次,有sum1=n2xsum_1 = n ^ {2} xsum1?=n2x。
我們假設其增加一則變成了sum2=(n+1)2x=n2x+(2n+1)xsum_2 = (n + 1) ^ {2} x = n ^ {2} x + (2 n + 1)xsum2?=(n+1)2x=n2x+(2n+1)x,其增量是(n<<1∣1)x(n << 1 | 1)x(n<<1∣1)x
我們再假設其減一則變成了sum3=(n?1)2x=n2x?(2(n?1)+1)xsum_3 = (n - 1) ^ {2} x = n ^ {2}x - (2(n - 1) + 1)xsum3?=(n?1)2x=n2x?(2(n?1)+1)x,其減少量是((n?1)<<1∣1)x((n - 1) << 1 | 1)x((n?1)<<1∣1)x
由此我們就推出了答案變換的公式了。
Coding
/*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> #define mp make_pair #define pb push_backusing namespace std;typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii;const double pi = acos(-1.0); const double eps = 1e-7; const int inf = 0x3f3f3f3f;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x; }const int N = 1e6 + 10;int n, m, block, a[N]; ll num[N], ans[N], now;struct Node {int l, r, id;bool operator < (const Node & t) const {return (l / block) != (t.l / block) ? l < t.l : ((l / block) & 1) ? r < t.r : r > t.r;} }ask[N];void add(int x) {now += (num[a[x]]++ << 1 | 1) * a[x]; } void del(int x) {now -= (--num[a[x]] << 1 | 1) * a[x]; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "r", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);n = read(), m = read();for(int i = 1; i <= n; i++) a[i] = read();block = sqrt(n);for(int i = 1; i <= m; i++) {ask[i].l = read(), ask[i].r = read();ask[i].id = i;}sort(ask + 1, ask + 1 + m);int l = 1, r = 0;for(int i = 1; i <= m; i++) {while(r < ask[i].r) add(++r);while(r > ask[i].r) del(r--);while(l < ask[i].l) del(l++);while(l > ask[i].l) add(--l);ans[ask[i].id] = now;}for(int i = 1; i <= m; i++) printf("%lld\n", ans[i]);return 0; }P1533 可憐的狗狗
Thinking
權值線段樹加莫隊。
題目給的數據表意不明,所以我們最好還是給aia_iai?離散化后,再進行權值的插入刪除操作。
這里的權值標記的是第iii只夠是否在區間里,如果在就標記為111,否則就刪去這個點變成000,對每個區間都完成了相應的操作,接下來我們就是要去查詢第KKK大的是什么,這里通過樹狀數組的前綴和性質對其進行二分,得到第kkk大的ididid,然后通過這個得到答案。
Coding
/*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> #define mp make_pair #define pb push_backusing namespace std;typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii;const double pi = acos(-1.0); const double eps = 1e-7; const int inf = 0x3f3f3f3f;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x; }const int N = 3e5 + 10;int a[N], b[N], id[N], n, m, block; int tree[N], ans[N];struct Node {int l, r, k, id;Node(int _l = 0, int _r = 0, int _k = 0, int _id = 0) : l(_l), r(_r), k(_k), id(_id) {}void input() {l = read(), r = read(), k = read();}bool operator < (const Node & t) const {return (l / block) != (t.l / block) ? l < t.l : ((l / block) & 1) ? r < t.r : r > t.r;} }ask[N];void update(int x, int value) {while(x <= n) {tree[x] += value;x += x & (-x);} }int query(int x) {int ans = 0;while(x) {ans += tree[x];x -= x & (-x);}return ans; }int find(int value) {int l = 1, r = n;while(l < r) {int mid = l + r >> 1;if(query(mid) < value) l = mid + 1;else r = mid;}return l; }void del(int x) {if(id[x]) update(id[x], -1);//if(id[x])是為了放置樹狀數組死循環而加上了的。 }void add(int x) {if(id[x]) update(id[x], 1); }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);n = read(), m = read(), block = sqrt(n);for(int i = 1; i <= n; i++) a[i] = b[i] = read();sort(b + 1, b + 1 + n);for(int i = 1; i <= n; i++) id[i] = lower_bound(b + 1, b + 1 + n, a[i]) - b;for(int i = 1; i <= m; i++) {ask[i].input();ask[i].id = i;}sort(ask + 1, ask + 1 + m);int l = 0, r = 0;for(int i = 1; i <= m; i++) {while(r > ask[i].r) del(r--);while(r < ask[i].r) add(++r);while(l < ask[i].l) del(l++);while(l > ask[i].l) add(--l);ans[ask[i].id] = find(ask[i].k);}for(int i = 1; i <= m; i++) printf("%d\n", b[ans[i]]);return 0; }Chika and Friendly Pairs
Thinking
這題與上一題的思想有異曲同工之處,離散化后莫隊,通過插入,刪除,區間查詢操作,來得到我們最后的答案。
Coding
/*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> #define mp make_pair #define pb push_backusing namespace std;typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii;const double pi = acos(-1.0); const double eps = 1e-7; const int inf = 0x3f3f3f3f;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x; }void print(ll x) {if(x < 10) {putchar(x + 48);return ;}print(x / 10);putchar(x % 10 + 48); }const int N = 3e4 + 10;int a[N], b[N], tree[N], n, m, k, block, all; ll sum, ans[N];struct Node {int l, r, id;bool operator < (const Node & t) const {return (l / block) != (t.l / block) ? l < t.l : ((l / block) & 1) ? r < t.r : r > t.r; } }ask[N];void update(int x, int value) {while(x <= n) {tree[x] += value;x += x & (-x);} }int query(int x) {int ans = 0;while(x) {ans += tree[x];x -= x & (-x);}return ans; }void del(int x) {//刪除點,以及對答案進行的影響操作。//我們不難發現出了這個點外在區間[b[x] - k, b[x] + k]里的點都會對答案進行貢獻影響。//所以我們刪除這個點后查詢query(r - 1) - query(l - 1)就是對答案的減小影響。update(x, -1);int l = lower_bound(b + 1, b + 1 + all, b[x] - k) - b;//這個點應該不用多說。int r = upper_bound(b + 1, b + 1 + all, b[x] + k) - b;//r是第一個大于b[x] + k的,所以r - 1是最后一個 <= b[x] + k的點。sum -= query(r - 1) - query(l - 1); }void add(int x) {update(x, 1);int l = lower_bound(b + 1, b + 1 + all, b[x] - k) - b;int r = upper_bound(b + 1, b + 1 + all, b[x] + k) - b;sum += query(r - 1) - query(l - 1) - 1; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);n = read(), m = read(), k = read(), block = sqrt(n);for(int i = 1; i <= n; i++) a[i] = b[i] = read();sort(b + 1, b + 1 + n);all = unique(b + 1, b + 1 + n) - (b + 1);for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + 1 + all, a[i]) - b;for(int i = 1; i <= m; i++) {ask[i].l = read(), ask[i].r = read();ask[i].id = i;}sort(ask + 1, ask + 1 + m);int l = 1, r = 0;for(int i = 1; i <= m; i++) {while(r > ask[i].r) del(a[r--]);while(r < ask[i].r) add(a[++r]);while(l > ask[i].l) add(a[--l]);while(l < ask[i].l) del(a[l++]);ans[ask[i].id] = sum;}for(int i = 1; i <= m; i++) print(ans[i]), putchar('\n');return 0; }可修改莫隊
P1903 [國家集訓隊]數顏色 / 維護隊列
Thinking
無非就是加了一個時間標記變成了有三個條件束縛,分別對l,r,tl, r, tl,r,t三個變量進行排序,接下來就是莫隊的基本操作了。
Coding
/*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> #define mp make_pair #define pb push_backusing namespace std;typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii;const double pi = acos(-1.0); const double eps = 1e-7; const int inf = 0x3f3f3f3f;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x; }void print(int x) {if(x < 10) {putchar(x + 48);return ;}print(x / 10);putchar(x % 10 + 48); }const int N = 1e6 + 10;int a[N], num[N], ans[N], n, q_time, c_time, block, m, sum;struct Change {int pos, pre, cur; }change[N];struct Query {int l, r, id, t;Query(int _l = 0, int _r = 0, int _id = 0, int _t = 0) : l(_l), r(_r), id(_id), t(_t) {}bool operator < (const Query & temp) const {return (l / block) != (temp.l / block) ? l < temp.l : (r / block) != (temp.r / block) ? r < temp.r : t < temp.t;} }ask[N];void add(int x) {sum += !num[a[x]]++; }void del(int x) {sum -= !--num[a[x]]; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);n = read(), m = read();for(int i = 1; i <= n; i++) a[i] = read();for(int i = 1; i <= m; i++) {char op = getchar();while(op != 'Q' && op != 'R') op = getchar();if(op == 'Q') {q_time++;ask[q_time].l = read(), ask[q_time].r = read();ask[q_time].id = q_time, ask[q_time].t = c_time;}else {c_time++;change[c_time].pos = read(), change[c_time].cur = read();change[c_time].pre = a[change[c_time].pos];a[change[c_time].pos] = change[c_time].cur;//這點一定要注意把a[pos]變成我們要改變的,因為后面可能再次改變這個點,所以他的pre應該是前一次已經改變后的狀態。}}for(int i = c_time; i >= 1; i--) a[change[i].pos] = change[i].pre;//注意從后向前恢復原狀。block = ceil(exp((log(n) + log(q_time)) / 3));int l = 0, r = 0, t = 0;sort(ask + 1, ask + 1 + q_time);for(int i = 1; i <= q_time; i++) {while(r > ask[i].r) del(r--);while(r < ask[i].r) add(++r);while(l > ask[i].l) add(--l);while(l < ask[i].l) del(l++);while(t < ask[i].t) {t++;int pos = change[t].pos;if(l <= pos && pos <= r)//同時滿足在l , r之間才能進行區間的篩選操作。del(pos);a[pos] = change[t].cur;//改變其值。if(l <= pos && pos <= r)add(pos);}while(t > ask[i].t) {int pos = change[t].pos;if(l <= pos && pos <= r)del(pos);a[pos] = change[t].pre;if(l <= pos && pos <= r)add(pos);t--;}ans[ask[i].id] = sum;}for(int i = 1; i <= q_time; i++) print(ans[i]), putchar('\n');return 0; }樹上莫隊
SP10707 COT2 - Count on a tree II
Thinking
設定兩個數組pre,sucpre,sucpre,suc數組,preipre_iprei?數組記錄的是節點iii第一次進入dfsdfsdfs的時間戳,sucisuc_isuci?記錄的是節點iii出dfsdfsdfs的時間戳。
如這個例子:
有節點權值及樹的形狀,滿足如下
105 2 9 3 8 5 7 7 1 2 1 3 1 4 3 5 3 6 3 7 4 8有歐拉序的排列如下。
1 4 8 8 4 3 7 7 6 6 5 5 3 2 2 1求2, 8的間的,不同的元素。
有lca(2,8)==1!=2,!=8lca(2, 8) == 1 != 2, != 8lca(2,8)==1!=2,!=8,有pre[2]=15>pre[8]=3pre[2] = 15 > pre[8] = 3pre[2]=15>pre[8]=3,所以我們取區間suc[8],pre[2]suc[8], pre[2]suc[8],pre[2]也就是
{8 4 3 7 7 6 6 5 5 3 2}?,成對出現的舍棄,最后{8 4 2} + lca(2, 8)剛好是2?>82->82?>8的最短路。所以我們維護的東西就簡單了。
再看一種情況,求1, 8之間,顯然有pre[1]<pre[8],lca(1,8)=1=minid(pre[x],pre[y])pre[1] < pre[8], lca(1, 8) = 1 = min_{id}(pre[x], pre[y])pre[1]<pre[8],lca(1,8)=1=minid?(pre[x],pre[y]),所以選定區間pre[1],pre[8]pre[1], pre[8]pre[1],pre[8]即{1, 4, 8}得到了1?>81 -> 81?>8的最短路。所以我們只需要特判lcalcalca就行了。
Coding
/*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc++.h> #define mp make_pair #define pb push_backusing namespace std;typedef long long ll; typedef unsigned long long ull; typedef pair<int, int> pii;const double pi = acos(-1.0); const double eps = 1e-7; const int inf = 0x3f3f3f3f;inline ll read() {ll f = 1, x = 0;char c = getchar();while(c < '0' || c > '9') {if(c == '-') f = -1;c = getchar();}while(c >= '0' && c <= '9') {x = (x << 1) + (x << 3) + (c ^ 48);c = getchar();}return f * x; }void print(ll x) {if(x < 10) {putchar(x + 48);return ;}print(x / 10);putchar(x % 10 + 48); }const int N = 1e5 + 10;int a[N], b[N], id[N], ans[N], num[N], n, m, block, sum; int fa[N], son[N], sz[N], dep[N], top[N], pre[N], suc[N], pos[N], tot; int head[N], to[N], nex[N], cnt = 1; bool flag[N];struct Node {int l, r, id, lca;bool operator < (const Node & t) const {return (l / block) != (t.l / block) ? l < t.l : (l / block) & 1 ? r < t.r : r > t.r;} }ask[N];void add(int x, int y) {to[cnt] = y;nex[cnt] = head[x];head[x] = cnt++; }void dfs1(int rt, int f) {pre[rt] = ++tot;pos[tot] = rt;sz[rt] = 1, fa[rt] = f;dep[rt] = dep[f] + 1;for(int i = head[rt]; i; i = nex[i]) {if(to[i] == f) continue;dfs1(to[i], rt);if(!son[rt] || sz[to[i]] > sz[son[rt]])son[rt] = to[i];sz[rt] += sz[to[i]];}suc[rt] = ++tot;pos[tot] = rt; }void dfs2(int rt, int tp) {top[rt] = tp;if(!son[rt]) return ;dfs2(son[rt], tp);for(int i = head[rt]; i; i = nex[i]) {if(to[i] == fa[rt] || to[i] == son[rt]) continue;dfs2(to[i], to[i]);} }int lca(int x, int y) {while(top[x] != top[y]) {if(dep[top[x]] < dep[top[y]]) swap(x, y);x = fa[top[x]];}return dep[x] < dep[y] ? x : y; }void add(int x) {sum += (++num[a[x]] == 1); }void del(int x) {sum -= (--num[a[x]] == 0); }void calc(int x) {if(!flag[x]) add(x);else del(x);flag[x] ^= 1; }int main() {// freopen("in.txt", "r", stdin);// freopen("out.txt", "w", stdout);// ios::sync_with_stdio(false), cin.tie(0), cout.tie(0);n = read(), m =read(), block = sqrt(2 * n);for(int i = 1; i <= n; i++) a[i] = b[i] = read();sort(b + 1, b + 1 + n);int all = unique(b + 1, b + 1 + n) - (b + 1);for(int i = 1; i <= n; i++) a[i] = lower_bound(b + 1, b + 1 + all, a[i]) - b;for(int i = 1; i < n; i++) {int x = read(), y = read();add(x, y);add(y, x);}dfs1(1, 0);dfs2(1, 1);for(int i = 1; i <= m; i++) {int x = read(), y = read();if(pre[x] > pre[y]) swap(x, y);ask[i].id = i, ask[i].lca = lca(x, y);if(ask[i].lca == x) {ask[i].l = pre[x];ask[i].r = pre[y];ask[i].lca = 0;}else {ask[i].l = suc[x];ask[i].r = pre[y];}}sort(ask + 1, ask + 1 + m);int l = 1, r = 0;for(int i = 1; i <= m; i++) {while(r > ask[i].r) calc(pos[r--]);while(r < ask[i].r) calc(pos[++r]);while(l > ask[i].l) calc(pos[--l]);while(l < ask[i].l) calc(pos[l++]);//lca不在區間里,所以add后需要馬上del。if(ask[i].lca) calc(pos[pre[ask[i].lca]]);ans[ask[i].id] = sum;if(ask[i].lca) calc(pos[pre[ask[i].lca]]);}for(int i = 1; i <= m; i++) print(ans[i]), putchar('\n');return 0; } 創作挑戰賽新人創作獎勵來咯,堅持創作打卡瓜分現金大獎總結
 
                            
                        - 上一篇: 剑三金水镇破案详细攻略
- 下一篇: LOL瑞兹技能详解
