莫队——三种题型

普通莫队

P3901 数列找不同

Thinking

一定是用可以用莫队来写题,这点是不用质疑的,所以那就简单了,只需要判断每次询问的区间是否满足r−l+1==numr - l + 1 == numrl+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<<11)x

我们再假设其减一则变成了sum3=(n−1)2x=n2x−(2(n−1)+1)xsum_3 = (n - 1) ^ {2} x = n ^ {2}x - (2(n - 1) + 1)xsum3=(n1)2x=n2x(2(n1)+1)x,其减少量是((n−1)<<1∣1)x((n - 1) << 1 | 1)x((n1)<<11)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,sucpresuc数组,preipre_iprei数组记录的是节点iii第一次进入dfsdfsdfs的时间戳,sucisuc_isuci记录的是节点iiidfsdfsdfs的时间戳。

如这个例子:

有节点权值及树的形状,满足如下

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;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/314524.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

P5357 【模板】AC自动机(二次加强版) fail树

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 思路&#xff1a; 这个只能搞failfailfail树了&#xff0c;让后跑一遍即可。 重复的字符串记一个&#xff0c;让后其他的都跟他一个答案即可。 // Problem: P3796 【模板】AC自动机&#xff08;加强版&…

10分钟了解一致性hash算法

应用场景当我们的数据表超过500万条或更多时&#xff0c;我们就会考虑到采用分库分表&#xff1b;当我们的系统使用了一台缓存服务器还是不能满足的时候&#xff0c;我们会使用多台缓存服务器&#xff0c;那我们如何去访问背后的库表或缓存服务器呢&#xff0c;我们肯定不会使用…

Educational Codeforces Round 114 (Rated for Div. 2) D. The Strongest Build 暴力 + bfs

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 你有nnn个装备槽&#xff0c;每个槽里面有cic_ici​个力量加成&#xff0c;对于每个槽只能选一个力量加成&#xff0c;现在给你mmm个力量组合[b1,b2,...,bn][b_1,b_2,...,b_n][b1​,b2​,...,bn​]代表这个力…

[SCOI2008]着色方案(DP)

题目链接 思想 显然我们后面的决策是跟前一步相关的&#xff0c;因此我们可以考虑DP&#xff0c;可以用一个15维的数组来进行转移&#xff0c;但是这样显然回mle&#xff0c;所以我们考虑如何压缩状态&#xff0c;由于1<Ci<51 < C_i < 51<Ci​<5&#xff0…

创业周年记:召唤神龙一周年小记

2018年8月8日&#xff0c;我决定离开腾讯的光环&#xff0c;辞职开始创业。《回顾4180天在腾讯使用C#的历程&#xff0c;开启新的征途》记录了我所说的拥有七龙珠&#xff0c;去召唤神龙&#xff0c;今天正好历时一年时间&#xff0c;非常有必要来回顾过去一年的创业历程。迎接…

1285. 单词 ac自动机 + fail树

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 一篇论文由若干单词构成&#xff0c;且单词间是隔开的&#xff0c;给你nnn个单词&#xff0c;要求你计算每个单词在论文中出现了多少次。 1≤n≤2001\le n\le 2001≤n≤200&#xff0c;所有单词总长不超过1e…

Bitset瞎搞

Bitset字符匹配 Regular Number /*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc.h> #define mp make_pair #define pb push_back #define endl \nusing namespace std;typedef long long ll; typedef unsigned long lo…

「数据ETL」从数据民工到数据白领蜕变之旅(三)-除了Excel催化剂之外PowerQuery新物种同样值得期待...

在自助式BI时代以前&#xff0c;Excel级别的数据ETL工作&#xff0c;非常低效&#xff0c;动不动就要启用VBA来完成一些常见的需求&#xff0c;自带的原生功能&#xff0c;未能满足大量的繁琐数据ETL刚需功能。在Excel2010后&#xff0c;PowerQuery以插件的形式横空出现&#x…

Codeforces Round #743 (Div. 2) D. Xor of 3 模拟 + 构造

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个010101序列aaa&#xff0c;定义一次操作是选择一个[1,n−2][1,n-2][1,n−2]范围内的下表&#xff0c;将ai,ai1,ai2a_i,a_{i1},a_{i2}ai​,ai1​,ai2​都变成ai⊕ai1⊕ai2a_i\oplus a_{i1} \oplus a_…

Docker系列之烹饪披萨(二)

上一篇我们讲解了虚拟机和容器的区别&#xff0c;本节我们来讲讲Docker中关于Dockerfile、镜像、容器等基本概念。Docker是一个在容器内开发、部署、运行应用程序的平台&#xff0c;Docker本质上是容器化的代名词&#xff0c;容器对于提高软件开发和数据科学的安全性&#xff0…

线段树平方和板子

题目测试链接 代码 /*Author : lifehappy */ #pragma GCC optimize(2) #pragma GCC optimize(3) #include <bits/stdc.h> #define mp make_pair #define pb push_back #define endl \n #define mid (l r >> 1) #define lson rt << 1, l, mid #define rson…

Codeforces Round #743 (Div. 2) E. Paint 区间dp + 暴力

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个有nnn个像素的图像&#xff0c;每个像素都有一个颜色aia_iai​&#xff0c;保证每种颜色的图像不会超过202020个。你现在每次可以选择一个颜色&#xff0c;并选择一段连续的像素&#xff0c;要求连续…

史上最能“拜客户教”的公司,是如何做到持续交付的?(第2趴)|DevOps案例研究...

内容来源&#xff1a;DevOps案例深度研究 –Amazon持续交付之道战队&#xff08;本文只展示部分PPT及研究成果&#xff0c;更多细节请关注案例分享会&#xff0c;及本公众号。&#xff09;本案例内容贡献者&#xff1a;单冰 (Topic Leader)、 赵栋、梁兴龙、李杰、毛艳清、牛恒…

C 简单瞎搞题(牛客练习赛22)(bitset优化dp)

Bitset优化Dp 题目链接 一般DP做法 显然后面的数是与前面的数字相关的&#xff0c;所以我们有dp数组&#xff0c;dp[i][j]dp[i][j]dp[i][j]选取了jjj个数&#xff0c;iii是否可以被创造出来&#xff0c;如果可以其值为1&#xff0c;否则为0。 所以我们显然有如下的状态转移…

AtCoder Regular Contest 125

传送门 A−DialUpA-Dial UpA−DialUp 贪心贪心贪心 首先当bbb有aaa没有的元素的时候显然无解&#xff0c;否则我们可以找到离a1a_1a1​最近的一个!a1!a_1!a1​&#xff0c;让后交替着来构造bbb即可。 int n,m; int a[N],b[N];int main() { // ios::sync_with_stdio(false); /…

ASP.NET Core on K8S深入学习(3)Deployment

上一篇《部署过程解析与安装Dashboard》中我们了解K8S的部署过程&#xff0c;这一篇我们来了解一下K8S为我们提供的几种应用运行方式&#xff1a;Deployment、DaemonSet与Job&#xff0c;它们是Kubernetes最重要的核心功能提供者。考虑到篇幅和更新速度&#xff0c;我将其分为两…

Codeforces Round #742 (Div. 2) F. One-Four Overload 构造 + 二分图染色

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个n∗mn*mn∗m的矩形&#xff0c;包含...和XXX&#xff0c;你有两种颜色&#xff0c;你需要给...染色使得每个XXX上下左右相邻的...其两种颜色个数相同&#xff0c;输出一种合法方案。 1≤n,m≤5001\l…

同余最短路(P3403 跳楼机)

同余最短路 前置 给定m个数&#xff0c;这m个数可以重复取&#xff0c;问最大的这m个数不能拼成的数&#xff0c;或者给定一定范围&#xff0c;范围里有多少个数是这m个数可以拼成的&#xff0c;对于这种问题我们可以考虑同余最短路的算法。 P3403 跳楼机 同余最短路介绍 …

8月语言排行:C#继续呈现增长态势

TIOBE 编程语言排行榜 8 月更新已公布&#xff0c;排名前十的分别是&#xff1a;Java, C, Python, C, C#, Visual Basic .NET, JavaScript, PHP, Objective-C 和 SQL。和上个月唯一的不同之处在于 Objective-C 和 SQL 的排名发生了交换。事实上&#xff0c;上周 Dice Insights …

Codeforces Round #538 (Div. 2) F. Please, another Queries on Array? 线段树 + 欧拉函数

传送门 文章目录题意&#xff1a;思路&#xff1a;题意&#xff1a; 给你一个序列aaa&#xff0c;你需要实现两种操作&#xff1a; (1)(1)(1) 将[l,r][l,r][l,r]的aia_iai​都乘rrr。 (2)(2)(2) 求ϕ(∏ilrai)mod1e97\phi(\prod_{il}^ra_i)\bmod 1e97ϕ(∏ilr​ai​)mod1e97 1…