bzoj3779 重组病毒 [lct+树链剖分]

3 篇文章 0 订阅
1 篇文章 0 订阅

Decsripiton:
给出一棵 n n 个节点的树,每一个节点开始有一个互不相同的颜色,初始根节点为1
定义一次感染为:将指定的一个节点到根的链上的所有节点染成一种新的颜色,代价为这条链上不同颜色的数目。
现有 m m 次操作,每次为一下三种之一:
RELEASEx:对 x x 执行一次感染;
RECENTERx:把根节点改为 x x ,并对原来的根节点执行一次感染;
REQUESTx:询问 x x 子树中所有节点感染代价的平均值。


Solution:
这些操作和lct有关,第一个操作是 access a c c e s s ,第二个操作跟轻重边有关,其实一个点的权值就是一个点到根的轻边的数量,那么考虑 access a c c e s s 的时候切换轻重边时更新子树。每次更新时要找到上一个 splay s p l a y 的最浅点,因为我们要更新的点在那棵 splay s p l a y 里,那么跟当前点连接的肯定是里面的最浅点。第三个操作查询子树即可。
有一个细节是刚开始的时候直接把所有点的父亲初始化就可以了。


这是一份过不了的代码,交了别人的代码。垃圾卡常出题人。

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e5 + 5;
int n, m;
inline int read() {
    int x = 0, f = 1;
    char c = getchar();
    while(!isdigit(c)) {
        if(c == '-') {
            f = -1;
        }
        c = getchar();
    }
    while(isdigit(c)) {
        x = x * 10 + c - '0';
        c = getchar();
    }
    return x * f;
}
namespace tr {
    struct edge {
        int nxt, to;
    } e[maxn * 2];
    int dfs_clock, rt, cnt;
    long long t1[maxn], t2[maxn];
    int Log[maxn], h[maxn], fa[maxn][21], mir[maxn], val[maxn], in[maxn], out[maxn];
    inline void link(int u, int v) {
        e[++cnt].nxt = h[u];
        h[u] = cnt;
        e[cnt].to = v;
    }
    void dfs(int u, int last) {
        in[u] = ++dfs_clock;
        mir[in[u]] = u;
        for(int i = h[u]; i; i = e[i].nxt) {
            if(e[i].to == last) {
                continue;
            }
            fa[e[i].to][0] = u;
            val[e[i].to] = val[u] + 1;
            dfs(e[i].to, u);
        }
        out[u] = dfs_clock;
    }
    inline void add(int x, int d) {
        long long p = x;
        for(; x <= n; x += x & -x) {
            t1[x] += d;
            t2[x] += p * d;
        }
    }
    inline long long Ask(int x) {
        long long s1 = 0, s2 = 0, p = x;
        for(; x; x -= x & -x) {
            s1 += t1[x];
            s2 += t2[x];
        }
        return (p + 1) * s1 - s2;
    }
    inline void update(int l, int r, int d) {
        if(l > r) {
            return;
        }
        add(r + 1, -d);
        add(l, d);
    }
    inline int query(int l, int r) {
        if(l > r) {
            return 0;
        }
        return Ask(r) - Ask(l - 1);
    }   
    void change(int x, int d) {
        if(rt == x) {
            update(1, n, d);
        } else if(in[rt] > in[x] && out[rt] < out[x]) {
            int p = rt;
            for(int i = Log[val[rt] - val[x]] ; ~i; --i) {
                if(val[fa[p][i]] > val[x]) {
                    p = fa[p][i];
                }
            }
            if(in[p] > 1) {
                update(1, in[p] - 1, d);
            }
            if(out[p] < n) {
                update(out[p] + 1, n, d);
            }           
        } else {
            update(in[x], out[x], d);       
        }
    }
} using namespace tr;
namespace lct {
    struct node {
        int f, rev;
        int ch[2];
    } t[maxn];
    inline int wh(int x) {
        return x == t[t[x].f].ch[1];
    }
    inline bool isr(int x) {
        return !t[x].f || (t[t[x].f].ch[0] != x && t[t[x].f].ch[1] != x);
    }
    inline void paint(int x) {
        t[x].rev ^= 1;
        swap(t[x].ch[0], t[x].ch[1]);
    }
    inline void pushdown(int x) {
        if(t[x].rev) {
            paint(t[x].ch[0]);
            paint(t[x].ch[1]);
            t[x].rev = 0;
        }
    }
    inline void pd(int x) {
        if(!isr(x)) {
            pd(t[x].f);
        }
        pushdown(x);
    }
void rotate(int x) {
        int y = t[x].f, z = t[y].f, w = wh(x);
        if(!isr(y)) {
            t[z].ch[wh(y)] = x;
        }
        t[x].f = z;
        t[y].f = x;
        t[t[x].ch[w ^ 1]].f = y;
        t[y].ch[w] = t[x].ch[w ^ 1];
        t[x].ch[w ^ 1] = y;
    } 
    inline void splay(int x) {
        pd(x);
        for(; !isr(x); rotate(x)) {
            if(wh(x) == wh(t[x].f)) {
                rotate(wh(x) == wh(t[x].f) ? t[x].f : x);
            }
        }
    }
    inline int findlow(int x) {
        splay(x);
        for(pushdown(x); t[x].ch[0]; x = t[x].ch[0], pushdown(x));
        return x;
    }
    inline void access(int x) {
        for(int y = 0, p; x; y = x, x = t[x].f) {
            splay(x);
            if(t[x].ch[1]) {
                p = t[x].ch[1];
                t[x].ch[1] = 0;             
                change(findlow(p), 1);
            }
            if(y) {
                change(findlow(y), -1);
            }
            t[x].ch[1] = y;
        }
    }
    inline void makert(int x) {
        access(x);
        splay(x);
        paint(x);
        rt = x;
    }
    inline double ask(int x) {
        if(rt == x) {
            return Ask(n) / (double)n;
        } else if(in[rt] > in[x] && out[rt] < out[x]) {
            int p = rt;
            for(int j = Log[val[rt] - val[x]]; ~j; --j) {
                if(val[fa[p][j]] > val[x]) {
                    p = fa[p][j];
                }
            }
            return (Ask(n) - query(in[p], out[p])) / (double)(n - out[p] + in[p] - 1);
        } else {
            return (query(in[x], out[x])) / (double)(out[x] - in[x] + 1);
        }
    }
}
int main() {
    n = read();
    m = read();
    for(int i = 1; i < n; ++i) {
        int u = read(), v = read();
        link(u, v);
        link(v, u);
    }
    val[1] = 1;
    dfs(rt = 1, 0);
    for(int j = 1; j <= 20; ++j) {
        for(int i = 1; i <= n; ++i) {
            fa[i][j] = fa[fa[i][j - 1]][j - 1];
        }
    }
    for(int i = 2; i <= n; ++i) {
        Log[i] = Log[i >> 1] + 1;
    }
    for(int i = 1; i <= n; ++i) {
        add(i, val[mir[i]] - val[mir[i - 1]]);
        lct::t[i].f = fa[i][0];
    }
    while(m--) {
        char opt[10];
        scanf("%s", opt);
        int x = read();
        if(opt[2] == 'L') {
            lct::access(x);
        } else if(opt[2] == 'C') {
            lct::makert(x);
        } else {
            printf("%.10f\n", lct::ask(x));
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值