题目链接
做了几道LCT,发现大多涉及到修改树上路径。本题也一样,4个操作中其实主要麻烦的就是加C和乘C,只需要维护区间和的同时记录加法和乘法的lazy标记,并且在pushdown的时候先乘再加即可。
1 #include2 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 }