BZOJ 2631 Tree LCT

13 篇文章 0 订阅

为了捡回记忆先写一道题。。
顺便把模板换成双旋的。以前写spaly掉RP掉光了。。
好慢啊。太懒了用link自作孽。。

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef unsigned int T;
const T mod = 51061, N = 100005;
int read() {
    int s = 0, f = 1; char ch = getchar();
    for (; ch < '0' || ch > '9'; ch = getchar()) if (ch == '-') f = -1;
    for (; '0' <= ch && ch <= '9'; ch = getchar()) s = s * 10 + ch - '0';
    return s * f;
}
int fa[N], rev[N], c[N][2], sk[N];
T mul[N], add[N], s[N], v[N], sz[N];
void update(int x) {
    s[x] = (s[c[x][0]] + s[c[x][1]] + v[x]) % mod;
    sz[x] = (sz[c[x][0]] + sz[c[x][1]] + 1) % mod;
}
void modify(int x, int a, int m) {
    v[x] = (v[x] * m + a) % mod;
    s[x] = (s[x] * m + a * sz[x]) % mod;
    add[x] = (add[x] * m + a) % mod;
    mul[x] = mul[x] * m % mod;
}
void push_down(int x) {
    if (rev[x]) {
        rev[c[x][0]] ^= 1;
        rev[c[x][1]] ^= 1;
        swap(c[x][0], c[x][1]);
        rev[x] = 0;
    }
    if (mul[x] != 1 || add[x] != 0) {
        modify(c[x][0], add[x], mul[x]);
        modify(c[x][1], add[x], mul[x]);
        mul[x] = 1; add[x] = 0;
    }
}
bool root(int x) {
    return c[fa[x]][0] != x && c[fa[x]][1] != x;
}
void rotate(int x, int k) {
    int y = fa[x], z = fa[y];
    c[y][k ^ 1] = c[x][k];
    fa[c[x][k]] = y; c[x][k] = y;
    fa[y] = x; fa[x] = z;
    if (c[z][0] == y) c[z][0] = x;
    else if (c[z][1] == y) c[z][1] = x;
    update(y); update(x);
}
void splay(int x) {
    int top = 0, i; sk[++top] = x;
    for (i = x; !root(i); i = fa[i]) sk[++top] = fa[i];
    while (top) push_down(sk[top--]);
    while (!root(x)) {
        int y = fa[x], z = fa[y];
             if (root(y)      && c[y][0] == x) rotate(x, 1);
        else if (root(y)      && c[y][1] == x) rotate(x, 0);
        else if (c[z][0] == y && c[y][0] == x) rotate(y, 1), rotate(x, 1);
        else if (c[z][0] == y && c[y][1] == x) rotate(x, 0), rotate(x, 1);
        else if (c[z][1] == y && c[y][0] == x) rotate(x, 1), rotate(x, 0);
        else if (c[z][1] == y && c[y][1] == x) rotate(y, 0), rotate(x, 0);
    }
}
void access(int x) {
    for (int t = 0; x; t = x, x = fa[x])
        splay(x), c[x][1] = t, update(x);
}
void makeroot(int x) {
    access(x); splay(x); rev[x] ^= 1;
}
void get_path(int x, int y) {
    makeroot(x); access(y); splay(y);
}
void link(int x, int y) {
    makeroot(x); fa[x] = y;
}
void cut(int x, int y) {
    get_path(x, y); c[y][0] = fa[x] = 0;
}

int main() {
    int i, n = read(), q = read(), a, b; char op[8];
    for (i = 1; i <= n; ++i) mul[i] = sz[i] = v[i] = s[i] = 1;
    for (i = 1; i < n; ++i) link(read(), read());
    while (q--) {
        scanf("%s", op);
        switch(op[0]) {
        case '+':
            a = read(); b = read();
            get_path(a, b);
            modify(b, read(), 1);
            break;
        case '-':
            cut(read(), read());
            link(read(), read());
            break;
        case '*':
            a = read(); b = read();
            get_path(a, b);
            modify(b, 0, read());
            break;
        case '/':
            a = read(); b = read();
            get_path(a, b);
            printf("%u\n", s[b]);
        }
    }
    return 0;
}

2631: tree

Description

 一棵n个点的树,每个点的初始权值为1。对于这棵树有q个操作,每个操作为以下四种操作之一:
+ u v c:将u到v的路径上的点的权值都加上自然数c;
- u1 v1 u2 v2:将树中原有的边(u1,v1)删除,加入一条新边(u2,v2),保证操作完之后仍然是一棵树;
* u v c:将u到v的路径上的点的权值都乘上自然数c;
/ u v:询问u到v的路径上的点的权值和,求出答案对于51061的余数。

Input

  第一行两个整数n,q
接下来n-1行每行两个正整数u,v,描述这棵树
接下来q行,每行描述一个操作

Output

  对于每个/对应的答案输出一行

Sample Input

3 2
1 2
2 3
* 1 3 4
/ 1 1

Sample Output

4

HINT

10%的数据保证,1<=n,q<=2000

另外15%的数据保证,1<=n,q<=5*10^4,没有-操作,并且初始树为一条链

另外35%的数据保证,1<=n,q<=5*10^4,没有-操作

100%的数据保证,1<=n,q<=10^5,0<=c<=10^4

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值