为了捡回记忆先写一道题。。
顺便把模板换成双旋的。以前写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