zoukankan      html  css  js  c++  java
  • 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("
    ");    */
    
        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("
    ");
        for(int i = 1; i <= n; i++)
            printf("%lld ", sumDis[i]);
        printf("
    ");    */
    
        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
    ", ans);
        }
        
        return 0;
    }
    View Code
  • 相关阅读:
    C#中的int?和X??
    验证码识别技术导论
    Jquery focus blur给文本框加选中离开效果
    Asp.Net 用户验证(自定义IPrincipal和IIdentity)
    FCKeditor介绍
    char varchar 有什么区别
    jquery无刷新载入其他页面的内容
    ASP.NET 安全认证
    程序员不是一般人
    [转]Asp.net中基于Forms验证的角色验证授权
  • 原文地址:https://www.cnblogs.com/CzxingcHen/p/9820491.html
Copyright © 2011-2022 走看看