3653: 谈笑风生

3653: 谈笑风生 

链接

分析:

  $ans = min(deep[x] - 1, k) * siz[x] - 1 +\sum\limits_{y是u子树内的点}(siz[y] - 1)$

  前面的可以$O(1)$算,后面的那一部分可以dfs序+主席树维护。

  或者dfs的过程中+线段树合并。或者长链剖分。

代码:

#include<cstdio>
#include<algorithm>
#include<cstring>
#include<iostream>
#include<cmath>
#include<cctype>
#include<set>
#include<queue>
#include<vector>
#include<map>
using namespace std;
typedef long long LL;

inline int read() {
    int x=0,f=1;char ch=getchar();for(;!isdigit(ch);ch=getchar())if(ch=='-')f=-1;
    for(;isdigit(ch);ch=getchar())x=x*10+ch-'0';return x*f;
}

const int N = 600005;
struct Edge{ int to, nxt; } e[N << 1];
int head[N], deep[N], fa[N], siz[N], st[N], ed[N], tr[N], En, Index, TimeIndex;
int ls[N * 20], rs[N * 20], Root[N];
LL sum[N * 20];

inline void add_edge(int u,int v) {
    ++En; e[En].to = v, e[En].nxt = head[u]; head[u] = En;
    ++En; e[En].to = u, e[En].nxt = head[v]; head[v] = En;
}
void dfs(int u) {
    deep[u] = deep[fa[u]] + 1;
    siz[u] = 1;
    st[u] = ++TimeIndex;tr[TimeIndex] = u;
    for (int i = head[u]; i; i = e[i].nxt) {
        int v = e[i].to;
        if (v == fa[u]) continue;
        fa[v] = u;
        dfs(v);
        siz[u] += siz[v];
    }
    ed[u] = TimeIndex;
}
void update(int l,int r,int last,int &now,int p) {
    if (!now) now = ++Index;
    sum[now] += sum[last] + siz[tr[p]] - 1; /// !!!
    if (l == r) return ;
    int mid = (l + r) >> 1;
    if (deep[tr[p]] <= mid) {
        rs[now] = rs[last];
        update(l, mid, ls[last], ls[now], p);
    } else {
        ls[now] = ls[last];
        update(mid + 1, r, rs[last], rs[now], p);
    }
}
LL query(int l,int r,int last,int now,int L,int R) {
    if (L <= l && r <= R) return sum[now] - sum[last];
    int mid = (l + r) >> 1; LL res = 0;
    if (L <= mid) res = query(l, mid, ls[last], ls[now], L, R);
    if (R > mid) res += query(mid + 1, r, rs[last], rs[now], L, R);
    return res;
}
int main() {
    int n = read(), Q = read(), D;
    for (int i = 1; i < n; ++i) {
        int u = read(), v = read();
        add_edge(u, v);
    }
    dfs(1);
    for (int i = 1; i <= n; ++i) D = max(D, deep[i]);
    for (int i = 1; i <= n; ++i) {
        update(1, D, Root[i - 1], Root[i], i);
    }
    LL ans = 0;
    while (Q--) {
        int x = read(), k = read();
        ans = 1ll * min(deep[x] - 1, k) * (siz[x] - 1);
        if (deep[x] < D) ans += query(1, D, Root[st[x]], Root[ed[x]], deep[x] + 1, min(D, deep[x] + k));
        printf("%lld\n", ans);
    }
    return 0;
}

 

posted @ 2019-01-18 16:29  MJT12044  阅读(168)  评论(0编辑  收藏  举报