做了几道LCT,发现大多涉及到修改树上路径。本题也一样,4个操作中其实主要麻烦的就是加C和乘C,只需要维护区间和的同时记录加法和乘法的lazy标记,并且在pushdown的时候先乘再加即可。
1 #include<bits/stdc++.h>
2 using namespace std;
3 typedef long long ll;
4 const unsigned int maxn = 120010;
5 const unsigned int mod = 51061;
6 unsigned int fa[maxn], ch[maxn][2], siz[maxn], val[maxn], sum[maxn], lr[maxn], lm[maxn], la[maxn], st[maxn];//父亲节点,左右儿子节点,当前子数节点个数,当前值,lr标记,辅助数组。
7 inline bool isroot(unsigned int x) {//判断x是否为所在splay的根
8 return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
9 }
10 inline void pushup(unsigned int x) {
11 sum[x] = (sum[ch[x][0]] + sum[ch[x][1]] + val[x]) % mod;
12 siz[x] = siz[ch[x][0]] + siz[ch[x][1]] + 1;
13 }
14 inline void pusha(unsigned int x, unsigned int c) {
15 sum[x] = (sum[x] + c * siz[x]) % mod;
16 val[x] = (val[x] + c) % mod;
17 la[x] = (la[x] + c) % mod;
18 }
19 inline void pushm(unsigned int x, unsigned int c) {
20 sum[x] = sum[x] * c%mod;
21 val[x] = val[x] * c%mod;
22 lm[x] = lm[x] * c%mod;
23 la[x] = la[x] * c%mod;
24 }
25 inline void pushr(unsigned int x) {
26 swap(ch[x][0], ch[x][1]);
27 lr[x] ^= 1;
28 }
29 inline void pushdown(unsigned int x) {
30 if (lm[x] != 1) {
31 if (ch[x][0])pushm(ch[x][0], lm[x]);
32 if (ch[x][1])pushm(ch[x][1], lm[x]);
33 lm[x] = 1;
34 }
35 if (la[x]) {
36 if (ch[x][0])pusha(ch[x][0], la[x]);
37 if (ch[x][1])pusha(ch[x][1], la[x]);
38 la[x] = 0;
39 }
40 if (lr[x]) {
41 if (ch[x][0])pushr(ch[x][0]);
42 if (ch[x][1])pushr(ch[x][1]);
43 lr[x] = 0;
44 }
45 }
46 inline void rotate(unsigned int x) {
47 unsigned int y = fa[x], z = fa[y];
48 unsigned int k = ch[y][1] == x;
49 if (!isroot(y))
50 ch[z][ch[z][1] == y] = x;
51 fa[x] = z; ch[y][k] = ch[x][k ^ 1]; fa[ch[x][k ^ 1]] = y;
52 ch[x][k ^ 1] = y; fa[y] = x;
53 pushup(y);
54 pushup(x);
55 }
56 inline void splay(unsigned int x) {
57 unsigned int f = x, len = 0;
58 st[++len] = f;
59 while (!isroot(f))st[++len] = f = fa[f];
60 while (len)pushdown(st[len--]);
61 while (!isroot(x)) {
62 unsigned int y = fa[x];
63 unsigned int z = fa[y];
64 if (!isroot(y))
65 rotate((ch[y][0] == x) ^ (ch[z][0] == y) ? x : y);
66 rotate(x);
67 }
68 pushup(x);
69 }
70 inline void access(unsigned int x) {//打通根节点到x的实链
71 for (unsigned int y = 0; x; x = fa[y = x])
72 splay(x), ch[x][1] = y, pushup(x);
73 }
74 inline void makeroot(unsigned int x) {//将x变为原树的根
75 access(x); splay(x); pushr(x);
76 }
77 unsigned int Findroot(unsigned int x) {//找根节点
78 access(x), splay(x);
79 while (ch[x][0])
80 pushdown(x), x = ch[x][0];
81 splay(x);
82 return x;
83 }
84 inline void split(unsigned int x, unsigned int y) {//将x到y路径变为play
85 makeroot(x); access(y); splay(y);
86 }
87 inline void Link(unsigned int x, unsigned int y) {//合法连边
88 makeroot(x); fa[x] = y;
89 }
90 inline void cut(unsigned int x, unsigned int y) {//合法断边
91 split(x, y); fa[x] = ch[y][0] = 0; pushup(y);
92 }
93 int main() {
94 unsigned int n, q;
95 unsigned int x, y, u, v;
96 scanf("%d%d", &n, &q);
97 for (unsigned int i = 1; i <= n; i++)val[i] = siz[i] = lm[i] = 1;
98 for (unsigned int i = 1; i < n; i++) {
99 scanf("%d%d", &x, &y);
100 Link(x, y);
101 }
102 while (q--) {
103 char s[2];
104 scanf("%s", s);
105 if (s[0] == '+') {
106 scanf("%d%d%d", &x, &y, &u);
107 split(x, y);
108 pusha(y, u);
109 }
110 else if (s[0] == '-') {
111 scanf("%d%d%d%d", &x, &y, &u, &v);
112 cut(x, y);
113 Link(u, v);
114 }
115 else if (s[0] == '*') {
116 scanf("%d%d%d", &x, &y, &u);
117 split(x, y);
118 pushm(y, u);
119 }
120 else if (s[0] == '/') {
121 scanf("%d%d", &x, &y);
122 split(x, y);
123 printf("%d\n", sum[y]);
124 }
125 }
126 }