[洛谷P1501][国家集训队]Tree II(LCT)

题目链接

做了几道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 }

 

posted @ 2019-08-26 20:57  祈梦生  阅读(169)  评论(0编辑  收藏  举报