Luogu 3241 [HNOI2015]开店

BZOJ 4012权限题

浙科协的网突然炸了,好慌……

据说正解是动态点分治,然而我并不会,我选择树链剖分 + 主席树维护。

设$dis_i$表示$i$到$root(1)$的值,那么对于一个询问$u$,答案为$\sum_{i = 1}^{n}dis_i + n * dis_u - 2 * \sum_{i = 1}^{n}dis_{lca(i, u)}$。

前两个东西很好维护,我们考虑如何维护后面这个$\sum$,对于每一个点我们可以把它到根跳一跳,然后把这个点对答案的贡献加到线段树中,如果再限定一个$[l, r]$的区间,只要把所有年龄排序从小到大排序按照贡献加到主席树中就可以了。

注意一条树链的贡献和线段树上区间的边界要搞清楚。

主席树标记永久化一下比较好,虽然感觉空间是开不下的,但是这题就这么过去了。

时间复杂度$O((n + q)log^2n)$。

Code:

#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
typedef long long ll;

const int N = 1.5e5 + 5;
const int M = 1e7 + 100;
const int inf = 1 << 30;

int n, qn, tot = 0, head[N], dfsc = 0, dep[N];
int top[N], fa[N], siz[N], son[N], id[N];
ll P, dis[N], toVal[N], sumE[N], sumDis[N];

struct Edge {
    int to, nxt;
    ll val;
} e[N << 1];

inline void add(int from, int to, ll val) {
    e[++tot].to = to;
    e[tot].val = val;
    e[tot].nxt = head[from];
    head[from] = tot;
}

struct Item {
    int age, id;

    friend bool operator < (const Item &x, const Item &y) {
        if(x.age == y.age) return x.id < y.id;
        else return x.age < y.age;
    }

} a[N];

template <typename T>
inline void read(T &X) {
    X = 0; char ch = 0; T op = 1;
    for(; ch > '9' || ch < '0'; ch = getchar())
        if(ch == '-') op = -1;
    for(; ch >= '0' && ch <= '9'; ch = getchar())
        X = (X << 3) + (X << 1) + ch - 48;
    X *= op;
}

inline void swap(int &x, int &y) {
    int t = x; x = y; y = t;
}

inline int max(int x, int y) {
    return x > y ? x : y;
} 

inline int min(int x, int y) {
    return x > y ? y : x;
}

void dfs1(int x, int fat, int depth, ll nowDis) {
    fa[x] = fat, dep[x] = depth;
    siz[x] = 1, dis[x] = nowDis;
    int maxson = -1;
    for(int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if(y == fat) continue;
        dfs1(y, x, depth + 1, nowDis + e[i].val);

        toVal[y] = e[i].val;
        siz[x] += siz[y];

        if(siz[y] > maxson) {
            maxson = siz[y];
            son[x] = y;
        }
    }
}

void dfs2(int x, int topf) {
    top[x] = topf, sumE[id[x] = ++dfsc] = toVal[x];
    if(!son[x]) return;
    dfs2(son[x], topf);
    for(int i = head[x]; i; i = e[i].nxt) {
        int y = e[i].to;
        if(y == fa[x] || y == son[x]) continue;
        dfs2(y, y);
    }
}

namespace PSegT {
    struct Node {
        int lc, rc;
        ll sum, cnt;
    } s[M];

    int root[N], nodeCnt = 0;

    #define lc(p) s[p].lc
    #define rc(p) s[p].rc
    #define sum(p) s[p].sum
    #define cnt(p) s[p].cnt
    #define mid ((l + r) >> 1)

    void ins(int &p, int l, int r, int x, int y, int pre) {
        s[p = ++nodeCnt] = s[pre];
        if(x <= l && y >= r) {
            ++cnt(p);
            return;
        }
        sum(p) += sumE[min(y, r)] - sumE[max(x, l) - 1];

        if(x <= mid) ins(lc(p), l, mid, x, y, lc(pre));
        if(y > mid) ins(rc(p), mid + 1, r, x, y, rc(pre));
    }

    ll query(int p, int l, int r, int x, int y) {
        ll res = 1LL * cnt(p) * (sumE[min(y, r)] - sumE[max(x, l) - 1]);
        if(x <= l && y >= r) return res + sum(p);

        if(x <= mid) res += query(lc(p), l, mid, x, y);
        if(y > mid) res += query(rc(p), mid + 1, r, x, y);

        return res;
    }

} using namespace PSegT;

inline void modify(int rt, int x) {
    for(; x; x = fa[top[x]]) 
        ins(root[rt], 1, n, id[top[x]], id[x], root[rt]);
}

inline ll solve(int rt, int x) {
    ll res = 0LL;
    for(; x; x = fa[top[x]]) 
        res += query(root[rt], 1, n, id[top[x]], id[x]);
   return res;
}

int main() {
//    freopen("Sample.txt", "r", stdin);
    
    read(n), read(qn), read(P);
    for(int i = 1; i <= n; i++) {
        read(a[i].age);
        a[i].id = i;
    }

    for(int i = 1; i < n; i++) {
        int x, y; ll v;
        read(x), read(y), read(v);
        add(x, y, v), add(y, x, v);
    }
    dfs1(1, 0, 1, 0LL), dfs2(1, 1);
    
/*    for(int i = 1; i <= n; i++)
        printf("%d ", top[i]);
    printf("\n");    */

    sort(a + 1, a + 1 + n);
    for(int i = 1; i <= n; i++) {
        sumE[i] += sumE[i - 1];
        sumDis[i] = sumDis[i - 1] + dis[a[i].id];
    }
    for(int i = 1; i <= n; i++) {
        root[i] = root[i - 1];
        modify(i, a[i].id);
    }
    
/*    for(int i = 1; i <= n; i++)
        printf("%lld ", sumE[i]);
    printf("\n");
    for(int i = 1; i <= n; i++)
        printf("%lld ", sumDis[i]);
    printf("\n");    */

    ll ans = 0LL;
    for(int x, l, r; qn--; ) {
        read(x), read(l), read(r);
        l = (1LL * l + ans) % P, r = (1LL * r + ans) % P;
        if(l > r) swap(l, r);

        l = lower_bound(a + 1, a + 1 + n, (Item) {l, 0}) - a;
        r = upper_bound(a + 1, a + 1 + n, (Item) {r, inf}) - a - 1;

        ans = 1LL * (r - l + 1) * dis[x] + sumDis[r] - sumDis[l - 1] - 2LL * (solve(r, x) - solve(l - 1, x));
        printf("%lld\n", ans);
    }
    
    return 0;
}
View Code

猜你喜欢

转载自www.cnblogs.com/CzxingcHen/p/9820491.html