BZOJ-4012 开店(动态树分治)

来源:互联网 发布:怎么把知乎转到微信 编辑:程序博客网 时间:2024/04/29 16:11

传送门:BZOJ-4012

题意:给定一棵树,每个点有一个颜色,多次询问颜色在[l,r]区间内的所有点与某个点之间的距离之和

又是一个数组开小T到怀疑人生系列。。(我怎么总是管不住这双手root数组只开MX呢)

一个经典的动态树分治题目,用树状数组保存每种颜色的节点到该层子树的根节点的距离,然后一层一层计算就行。

= =本来应该是这样的,后来看了下发现颜色有n种,n^2logn的树状数组肯定爆内存啊。

后来想了下,明明只要记录区间内的值,用个vector弄下前缀和不就行了吗。。。(哈希都省去了

#include<cstdio>#include<string.h>#include<algorithm>#include<vector>using namespace std;typedef long long LL;typedef pair<int, int> PII;const int MX = 150005;const int MXM = MX * 40;const int inf = 0x3f3f3f3f;struct Edge {    int v, w, nxt;} E[MX * 2];int head[MX], tot;struct node {    int rt, subrt, nxt;    LL dis;} root[MXM];struct p {    int x;    LL y, cnt;    p(int x = 0, LL y = 0, LL cnt = 0): x(x), y(y), cnt(cnt) {}    bool operator<(const p& _A)const {        return x < _A.x;    }};int fir[MX], rear;int a[MX], vis[MX], sz[MX], id[MX];int n, Root, Maxv, cnt;vector<p>T[MX << 2], tmp;void init() {    memset(head, -1, sizeof(head));    memset(fir, -1, sizeof(fir));    memset(vis, 0, sizeof(vis));    tot = rear = cnt = 0;}void add_edge(int u, int v, int w) {    E[tot].v = v;    E[tot].w = w;    E[tot].nxt = head[u];    head[u] = tot++;}void add_root(int u, int rt, int subrt, LL dis) {    root[rear].rt = rt;    root[rear].subrt = subrt;    root[rear].dis = dis;    root[rear].nxt = fir[u];    fir[u] = rear++;}void dfs_size(int u, int fa) {    sz[u] = 1;    for (int i = head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v] || v == fa) continue;        dfs_size(v, u);        sz[u] += sz[v];    }}void dfs_root(int u, int fa, int rt) {    if (max(sz[u], sz[rt] - sz[u]) < Maxv) {        Maxv = max(sz[u], sz[rt] - sz[u]);        Root = u;    }    for (int i = head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v] || v == fa) continue;        dfs_root(v, u, rt);    }}p arr[MX];void cal(int u) {    if (T[u].empty()) return;    sort(T[u].begin(), T[u].end());    int sz = 0;    arr[++sz] = p(-1, 0, 0);    for (int i = 0; i < T[u].size(); i++) {        if (T[u][i].x != arr[sz].x) {            arr[++sz].x = T[u][i].x;            arr[sz].y = arr[sz - 1].y + T[u][i].y;            arr[sz].cnt = arr[sz - 1].cnt + 1;        } else {            arr[sz].y += T[u][i].y;            arr[sz].cnt++;        }    }    T[u].resize(sz);    for (int i = 1; i <= sz; i++) T[u][i - 1] = arr[i];}void dfs_tree(int u, int fa, int rt, int subrt, LL dir) {    add_root(u, rt, subrt, dir);    T[rt].push_back(p(a[u], dir, 1));    T[subrt].push_back(p(a[u], dir, 1));    for (int i = head[u]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v] || v == fa) continue;        dfs_tree(v, u, rt, subrt, dir + E[i].w);    }}void dfs(int u) {    Root = 0; Maxv = n;    dfs_size(u, -1); dfs_root(u, -1, u);    vis[Root] = 1; id[Root] = ++cnt;    T[cnt].clear();    T[cnt].push_back(p(a[Root], 0, 1));    add_root(Root, id[Root], 0, 0);    for (int i = head[Root]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v]) continue;        T[++cnt].clear();        dfs_tree(v, Root, id[Root], cnt, E[i].w);        cal(cnt);    }    cal(id[Root]);    for (int i = head[Root]; ~i; i = E[i].nxt) {        int v = E[i].v;        if (vis[v]) continue;        dfs(v);    }}p Query(int rt, int l, int r) {    if (T[rt].empty()) return p();    int p1 = lower_bound(T[rt].begin(), T[rt].end(), p(l)) - T[rt].begin() - 1;    int p2 = upper_bound(T[rt].begin(), T[rt].end(), p(r)) - T[rt].begin() - 1;    return p(0, T[rt][p2].y - T[rt][p1].y, T[rt][p2].cnt - T[rt][p1].cnt);}LL query(int u, int l, int r) {    LL ret = 0;    for (int i = fir[u]; ~i; i = root[i].nxt) {        int rt = root[i].rt, subrt = root[i].subrt, dis = root[i].dis;        p p1 = Query(rt, l, r);        p p2 = Query(subrt, l, r);        ret += p1.y - p2.y + (p1.cnt - p2.cnt) * dis;    }    return ret;}int main() {    int m, A;    //freopen("in.txt", "r", stdin);    scanf("%d%d%d", &n, &m, &A);    init();    for (int i = 1; i <= n; i++) scanf("%d", &a[i]);    for (int i = 1, u, v, w; i < n; i++) {        scanf("%d%d%d", &u, &v, &w);        add_edge(u, v, w); add_edge(v, u, w);    }    dfs(1);    LL ans = 0;    for (int i = 1, u, l, r; i <= m; i++) {        scanf("%d%d%d", &u, &l, &r);        l = (l + ans) % A;        r = (r + ans) % A;        if (l > r) swap(l, r);        printf("%lld\n", ans = query(u, l, r));    }    return 0;}


原创粉丝点击