【gdoi2018 day1】涛涛接苹果

题目大意:

太长了,不想写。

题解:

看到这个子树问题,很容易想到dfs序转区间。

再写写约束,发现有三个,并且满足容斥性。

于是排序搞掉一个,cdq搞掉一个,树状数组搞掉一个,贼好写。

主席树,K-D Tree当然也可以,有些复杂。

Code:

#include 
#include
#define low(a) ((a) & -(a))
#define ll long long
#define fo(i, x, y) for(int i = x; i <= y; i ++)
using namespace std;

const int N = 3e5 + 5;

int n, m, Q, x, y, tq; ll ans[N];
int final[N], to[N], next[N], tot;
int dep[N], bz[N], p[N], q[N], td;

struct node {
    int i, t, x, w;
} a[N];

void link(int x, int y) {
    next[++ tot] = final[x], to[tot] = y, final[x] = tot;
    next[++ tot] = final[y], to[tot] = x, final[y] = tot;
}

void dg(int x) {
    bz[x] = 1; p[x] = ++ td;
    for(int i = final[x]; i; i = next[i]) {
        int y = to[i]; if(bz[y]) continue;
        dep[y] = dep[x] + 1; dg(y);
    }
    q[x] = td;
}

int cmp(node a, node b) {
    if(a.t < b.t) return 1;
    if(a.t > b.t) return 0;
    return a.i > b.i;
}

ll f[N];

void add(int x, int w) {
    while(x <= n) f[x] += w, x += low(x);
}

ll find(int x) {
    ll s = 0; while(x) s += f[x], x -= low(x);
    return s;
}

int cmp2(node a, node b) {
    return dep[a.x] + a.t > dep[b.x] + b.t;
}

void dg(int x, int y) {
    if(x == y) return;
    int m = x + y >> 1;
    dg(x, m); dg(m + 1, y);
    int l = x;
    fo(i, m + 1, y) if(a[i].i) {
        while(l <= m && a[l].t + dep[a[l].x] + 1 >= a[i].t + dep[a[i].x]) {
            if(!a[l].i) add(p[a[l].x], a[l].w);
            l ++;
        }
        ans[a[i].i] += find(q[a[i].x]) - find(p[a[i].x] - 1);
    }
    fo(i, x, l - 1) if(!a[i].i) add(p[a[i].x], -a[i].w);
    sort(a + x, a + y + 1, cmp2);
}

int main() {
    freopen("appletree.in", "r", stdin);
    freopen("appletree.out", "w", stdout);
    scanf("%d %d %d", &n, &m, &Q);
    fo(i, 1, n) {
        tq ++; a[tq].i = 0; a[tq].t = 0; a[tq].x = i;
        scanf("%d", &a[tq].w);
    }
    fo(i, 1, n - 1) {
        scanf("%d %d", &x, &y);
        link(x, y);
    }
    dep[1] = 1; dg(1);
    fo(i, 1, m) {
        a[++ tq].i = 0;
        scanf("%d %d %d", &a[tq].t, &a[tq].x, &a[tq].w);
    }
    fo(i, 1, Q) {
        a[++ tq].i = i;
        scanf("%d %d", &a[tq].t, &a[tq].x);
    }
    sort(a + 1, a + tq + 1, cmp);
    dg(1, tq);

    fo(i, 1, Q) printf("%lld\n", ans[i]);
}

你可能感兴趣的:(线段树,cdq分治)