[BZOJ]3159 决战 LCT&Splay

3159: 决战

Time Limit: 10 Sec  Memory Limit: 512 MB
Submit: 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

Sample Output

0

0

6

3

19

HINT

1<=N,M<=50000.且对于运送操作1<=W<=1000

Source

[ Submit][ Status][ Discuss]


HOME Back

题解

  很明显前四个操作都能通过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);
    }
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值