3159: 决战
Time Limit: 10 Sec Memory Limit: 512 MBSubmit: 420 Solved: 183
[ Submit][ Status][ Discuss]
Description
Input
第一行有三个整数N、M和R,分别表示树的节点数、指令和询问总数,以及X国的据点。
接下来N-1行,每行两个整数X和Y,表示Katharon国的一条道路。
接下来M行,每行描述一个指令或询问,格式见题目描述。
Output
对于每个询问操作,输出所求的值。
Sample Input
5 8 1
1 2
2 3
3 4
4 5
Sum 2 4
Increase 3 5 3
Minor 1 4
Sum 4 5
Invert 1 3
Major 1 2
Increase 1 5 2
Sum 1 5
1 2
2 3
3 4
4 5
Sum 2 4
Increase 3 5 3
Minor 1 4
Sum 4 5
Invert 1 3
Major 1 2
Increase 1 5 2
Sum 1 5
Sample Output
0
0
6
3
19
0
6
3
19
HINT
1<=N,M<=50000.且对于运送操作1<=W<=1000
Source
题解
很明显前四个操作都能通过LCT或者树链剖分来做. 考虑第五个操作. 如果用LCT来做的话链反转打rev标记? 不. 实际上这个等价于makeroot了, 这就不是链反转了. 所以考虑再用一个splay森林来维护LCT. 这个splay是用来维护值的. 那么LCT里的每个点映射到splay森林里所对应点的值. LCT的分裂和合并的时候, 找到对应splay的根进行相同的分裂和合并. 具体见代码. rt数组即为LCT里对应的splay的根.
#include<bits/stdc++.h>
#define ls c[x][0]
#define rs c[x][1]
#define smin(x, y) x = min(x, y)
#define smax(x, y) x = max(x, y)
using namespace std;
typedef long long lnt;
const int maxn = 5e4 + 5;
int n, Q, num, R;
int h[maxn];
char ss[12];
struct edge{ int nxt, v;}e[maxn * 2];
inline void add(int u, int v)
{
e[++ num].v = v, e[num].nxt = h[u], h[u] = num;
e[++ num].v = u, e[num].nxt = h[v], h[v] = num;
}
struct Tsplay
{
int top;
bool rev[maxn];
int c[maxn][2], fa[maxn], tag[maxn], siz[maxn], pdsT[maxn];
lnt sum[maxn], mins[maxn], maxs[maxn], val[maxn];
inline void init(int x) {siz[x] = 1;}
inline bool isroot(int x) { return !fa[x];}
inline void add(int x, int v)
{
if(x)
sum[x] += 1ll * v * siz[x], tag[x] += v, mins[x] += v, maxs[x] += v, val[x] += v;
}
inline void rever(int x) {swap(ls, rs); rev[x] ^= 1;}
inline void update(int x)
{
siz[x] = 1;
mins[x] = maxs[x] = sum[x] = val[x];
siz[x] += siz[ls], smin(mins[x], mins[ls]), smax(maxs[x], maxs[ls]), sum[x] += sum[ls];
siz[x] += siz[rs], smin(mins[x], mins[rs]), smax(maxs[x], maxs[rs]), sum[x] += sum[rs];
}
inline void pushdown(int x)
{
if (tag[x])
add(ls, tag[x]), add(rs, tag[x]), tag[x] = 0;
if (rev[x])
rever(ls), rever(rs), rev[x] = 0;
}
inline void rotate(int x)
{
int y = fa[x], z = fa[y];
int l = (c[y][1] == x), r = l ^ 1;
if (!isroot(y)) c[z][c[z][1] == y] = x;
fa[x] = z, fa[y] = x, fa[c[x][r]] = y;
c[y][l] = c[x][r], c[x][r] = y;
update(y), update(x);
}
inline void splay(int x)
{
top = 0;
pdsT[++ top] = x;
for (int i = x; ! isroot(i); i = fa[i]) pdsT[++ top] = fa[i];
for (int i = top; i; -- i) pushdown(pdsT[i]);
for (int f; !isroot(x); rotate(x))
if(!isroot(f = fa[x]))
rotate((c[fa[f]][0] == f ^ c[f][0] == x) ? f : x);
}
inline int findrt(int &x)
{
while (fa[x]) x = fa[x];
return x;
}
void find(int &x,int rank){
while (true)
{
pushdown(x);
if (rank <= siz[ls]) x = ls;
else if (rank==siz[ls] + 1) return;
else rank -= (siz[ls]+1), x = rs;
}
}
}Val;
struct Lct_For_shape
{
int top;
bool rev[maxn];
int c[maxn][2], siz[maxn], fa[maxn], rt[maxn], pdsT[maxn];
inline void init(int x, int f)
{ fa[x] = f, rt[x] = x, siz[x] = 1; Val.init(x); }
inline bool isroot(int x){ return c[fa[x]][0] != x && c[fa[x]][1] != x;}
inline void update(int x){ siz[x] = siz[ls] + siz[rs] + 1; }
inline void rever(int x) {swap(ls, rs); rev[x] ^= 1;}
inline void pushdown(int x)
{
if (rev[x])
rever(ls), rever(rs), rev[x] = 0;
}
inline void rotate(int x)
{
int y = fa[x], z = fa[y];
int l = (c[y][1] == x), r = l ^ 1;
if (!isroot(y)) c[z][c[z][1] == y] = x;
fa[x] = z, fa[y] = x, fa[c[x][r]] = y;
c[y][l] = c[x][r], c[x][r] = y;
update(y), update(x);
}
inline void splay(int x)
{
top = 0;
pdsT[++ top] = x;
for (int i = x; ! isroot(i); i = fa[i]) pdsT[++ top] = fa[i];
for (int i = top; i; -- i) pushdown(pdsT[i]);
rt[x] = rt[pdsT[top]];
for (int f; !isroot(x); rotate(x))
if(!isroot(f = fa[x]))
rotate((c[fa[f]][0] == f ^ c[f][0] == x) ? f : x);
}
inline void access(int x)
{
for (int y = 0; x; x = fa[x])
{
splay(x);
int xx = Val.findrt(rt[x]), yy = Val.findrt(rt[y]);
if (!y) yy = 0;
Val.find(xx, siz[ls] + 1), Val.splay(xx), rt[x] = xx;
rt[rs] = Val.c[xx][1], Val.fa[Val.c[xx][1]] = 0;
Val.c[xx][1] = yy, Val.fa[yy] = xx, Val.update(xx);
rs = y, update(x), y = x;
}
}
inline void makeroot(int x)
{
access(x), splay(x);
rever(x), Val.rever(rt[x]);
}
inline void split(int x, int y)
{ makeroot(x), access(y); }
}lct;
void dfs(int u, int f)
{
lct.init(u, f);
for (int i = h[u]; i; i = e[i].nxt)
if (e[i].v != f) dfs(e[i].v, u);
}
int main()
{
int x, y, z, vy;
Val.mins[0] = (lnt) 1 << 62, Val.maxs[0] = 0;
scanf("%d%d%d", &n, &Q, &R);
for (int i = 1; i < n; ++ i) scanf("%d%d", &x, &y), add(x, y);
dfs(R, 0);
for (int i = 1; i <= Q; ++ i)
{
scanf("%s", ss);
scanf("%d%d", &x, &y);
lct.split(x, y), vy = Val.findrt(lct.rt[y]);
if (ss[2] == 'c') scanf("%d", &z), Val.add(vy, z);
else if (ss[2] == 'm') printf("%lld\n", Val.sum[vy]);
else if (ss[2] == 'j') printf("%lld\n", Val.maxs[vy]);
else if (ss[2] == 'n') printf("%lld\n", Val.mins[vy]);
else Val.rever(vy);
}
}