[BZOJ-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的余数。

Solution

LCT的模板题

Notice

注意Link和Cut的时候不用判是否联通,否则会TLE。
还有要用unsigned int,int会爆,longlong会被卡常。

Code

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define sqz main
#define ll long long
#define rep(i, a, b) for (int i = (a); i <= (b); i++)
#define per(i, a, b) for (int i = (a); i >= (b); i--)
#define Rep(i, a, b) for (int i = (a); i < (b); i++)
#define travel(i, u) for (int i = head[u]; ~i; i = edge[i].next)

const ll INF = 1e9, Mo = 51061;
const int N = 100000;
const double eps = 1e-6;
namespace slow_IO
{
ll read()
{
ll x = 0; int zf = 1; char ch = getchar();
while (ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
if (ch == '-') zf = -1, ch = getchar();
while (ch >= '0' && ch <= '9') x = x * 10 + ch - '0', ch = getchar();
return x * zf;
}
void write(ll y)
{
if (y < 0) putchar('-'), y = -y;
if (y > 9) write(y / 10);
putchar(y % 10 + '0');
}
}
using namespace slow_IO;

char st[5];
struct LinkCutTree
{
int Fa[N + 5], Son[N + 5][2], rev[N + 5], Size[N + 5], Stack[N + 5], top;
unsigned Sum[N + 5], Val[N + 5], Mul[N + 5], Add[N + 5];
inline void Modify(int u, int a, int m)
{
if (!u) return;
Sum[u] = (Sum[u] * m + Size[u] * a) % Mo;
Val[u] = (Val[u] * m + a) % Mo;
Mul[u] = (Mul[u] * m) % Mo;
Add[u] = (Add[u] * m + a) % Mo;
}
inline void up(int u)
{
Size[u] = (Size[Son[u][0]] + Size[Son[u][1]] + 1) % Mo;
Sum[u] = (Sum[Son[u][0]] + Sum[Son[u][1]] + Val[u]) % Mo;
}
inline void down(int u)
{
if (rev[u])
{
rev[Son[u][0]] ^= 1, rev[Son[u][1]] ^= 1, rev[u] ^= 1;
swap(Son[u][0], Son[u][1]);
}
if (Add[u] != 0 || Mul[u] != 1)
{
Modify(Son[u][0], Add[u], Mul[u]);
Modify(Son[u][1], Add[u], Mul[u]);
}
Add[u] = 0, Mul[u] = 1;
}
inline int isroot(int u)
{
return (Son[Fa[u]][0] != u && Son[Fa[u]][1] != u);
}

inline void Rotate(int x)
{
int y = Fa[x], z = Fa[y];
int l = Son[y][1] == x, r = l ^ 1;
if (!isroot(y)) Son[z][Son[z][1] == y] = x;
Son[y][l] = Son[x][r], Fa[Son[x][r]] = y;
Son[x][r] = y, Fa[y] = x, Fa[x] = z;
up(y), up(x);
}
inline void Splay(int x)
{
Stack[top = 1] = x;
for (int y = x; !isroot(y); y = Fa[y]) Stack[++top] = Fa[y];
per(i, top, 1) down(Stack[i]);
while (!isroot(x))
{
int y = Fa[x], z = Fa[y];
if (!isroot(y))
{
if ((Son[z][1] == y) ^ (Son[y][1] == x)) Rotate(x);
else Rotate(y);
}
Rotate(x);
}
}

inline void Access(int u)
{
for (int last = 0; u; last = u, u = Fa[u])
Splay(u), Son[u][1] = last, up(u);
}
inline void Make_Root(int u)
{
Access(u), Splay(u), rev[u] ^= 1;
}
inline int Find_Root(int u)
{
Access(u), Splay(u);
while (Son[u][0]) u = Son[u][0];
return u;
}

inline void Split(int x, int y)
{
Make_Root(x), Access(y), Splay(y);
}
inline void Link(int x, int y)
{
Make_Root(x);
Fa[x] = y;
}
inline void Cut(int x, int y)
{
Make_Root(x); Access(y); Splay(y);
Fa[x] = Son[y][0] = 0;
}
}LCT;

int sqz()
{
int n = read(), m = read();
rep(i, 1, n) LCT.Val[i] = LCT.Mul[i] = 1;
Rep(i, 1, n) LCT.Link((int)read(), (int)read());
while (m--)
{
scanf("%s", st);
if (st[0] == '+')
{
int x = read(), y = read(), z = read();
LCT.Split(x, y), LCT.Modify(y, z, 1);
}
if (st[0] == '-')
{
int x1 = read(), y1 = read(), x2 = read(), y2 = read();
LCT.Cut(x1, y1), LCT.Link(x2, y2);
}
if (st[0] == '*')
{
int x = read(), y = read(), z = read();
LCT.Split(x, y), LCT.Modify(y, 0, z);
}
if (st[0] == '/')
{
int x = read(), y = read();
LCT.Split(x, y); printf("%u\n", LCT.Sum[y]);
}
}
return 0;
}
文章目录
  1. 1. Description
  2. 2. Solution
  3. 3. Notice
  4. 4. Code