[JOISC2018]道路建设 LCT

[JOISC2018]道路建设

LOJ传送门

考的时候打的大暴力,其实想到了LCT,但是思路有点没转过来。就算想到了估计也不能切,我没有在考场写LCT的自信。。。

其实这题不是让你直接用LCT维护答案,只是借用了LCT的架构,让权值相同的点在同一棵splay中,用一棵splay顶端的点的权值表示这棵splay中所有点的权值。发现从根到某个点的操作跟LCT的access操作相似,可以把access操作魔改一下,一边splay、跳父亲,一边更新树状数组、统计答案。注意为了维护一棵splay的权值,rotate转到根的时候要更新根的权值。

代码非常简短:

#include <cstdio>
#include <cctype>
#include <algorithm>
#define R register
#define I inline
#define L long long
#define B 1000000
using namespace std;
const int N = 100003;
char buf[B], *p1, *p2;
I char gc() { return p1 == p2 && (p2 = (p1 = buf) + fread(buf, 1, B, stdin), p1 == p2) ? EOF : *p1++; }
I int rd() {
    R int f = 0;
    R char c = gc();
    while (c < 48 || c > 57)
        c = gc();
    while (c > 47 && c < 58)
        f = f * 10 + (c ^ 48), c = gc();
    return f;
}
L o;
int a[N], c[N], b[N], v[N], n, t;
struct T{int p, d[2], f, s;}e[N];
I void mdf(int x, int k) {
    for (; x <= n; b[x] += k, x += x & -x)
        if (v[x] ^ t)
            v[x] = t, b[x] = 0;
}
I int qry(int x) {
    R int r = 0;
    for (; x; x ^= x & -x)
        if (v[x] == t)
            r += b[x];
    return r;
}
I int nrt(int x) { return e[e[x].p].d[0] == x || e[e[x].p].d[1] == x; }
I void upd(int x) { e[x].s = e[e[x].d[0]].s + e[e[x].d[1]].s + 1; }
I void rtt(int x) {
    R int f = e[x].p, g = e[f].p, b = e[f].d[0] == x, c = e[x].d[b];
    if (nrt(f))
        e[g].d[e[g].d[1] == f] = x;
    else
        e[x].f = e[f].f;
    if (c)
        e[c].p = f;
    e[x].p = g, e[f].p = x, e[x].d[b] = f, e[f].d[!b] = c, upd(f);
}
I void spl(int x) {
    R int f, g;
    for (;nrt(x); rtt(x)) {
        f = e[x].p, g = e[f].p;
        if (nrt(f))
            rtt((e[g].d[1] == f) ^ (e[f].d[1] == x) ? x : f);
    }
    upd(x);
}
I void acc(int x) {
    for (R int y = 0; x; x = e[y = x].p)
        spl(x), e[e[x].d[1]].f = e[x].f, o += 1ll * (e[e[x].d[0]].s + 1) * qry(e[x].f - 1), mdf(e[x].f, e[e[x].d[0]].s + 1), e[x].d[1] = y, upd(x);
}
int main() {
    R int i, x, y;
    n = rd();
    for (i = 1; i <= n; ++i)
        c[i] = rd(), a[i] = c[i];
    sort(a + 1, a + n + 1);
    for (i = 1; i <= n; ++i)
        e[i].f = lower_bound(a + 1, a + n + 1, c[i]) - a;
    for (i = 1; i < n; ++i)
        x = rd(), y = rd(), ++t, o = 0, acc(x), spl(x), e[x].p = y, e[y].d[0] = x, upd(y), printf("%I64d\n", o);
    return 0;
}

换Windows了,%I64d就懒得改了。

转载于:https://www.cnblogs.com/cj-chd/p/10276991.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值