bzoj3626

树链剖分+离线

思路很好

看见这种题肯定知道不能直接求,就得在lca上搞事情

将询问拆成两个,排序,然后离线不断从i=1-n到根的路径上全部+1,每次询问就询问从z到根的路径和

我们想一想,就可以知道z和i,将i到根的路径全部+1,那么lca的深度就是z到根的权值和,而且这个权值和满足可加性,那么我们把询问拆成两个,1-l-1,1-r,相减就是答案

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int N = 50010, mod = 201314;
int n, Q, tot, cnt;
ll ans[N];
int dfn[N], top[N], size[N], son[N], fa[N], dep[N];
vector<int> G[N];
struct query {
    int p, z, id, add;
    bool friend operator < (query A, query B)
    {
        return A.p < B.p;
    }
} q[N << 1];
struct seg {
    int tree[N << 2], tag[N << 2];
    void pushdown(int x, int l, int r)
    {
        if(!tag[x]) return;
        int mid = (l + r) >> 1;
        tree[x << 1] += (mid - l + 1) * tag[x];
        tree[x << 1 | 1] += (r - mid) * tag[x];
        tag[x << 1] += tag[x];
        tag[x << 1 | 1] += tag[x];
        tag[x] = 0;
    }
    void update(int l, int r, int x, int a, int b, int delta)
    {
        if(l > b || r < a) return;
        if(l >= a && r <= b)
        {
            tag[x] += delta;
            tree[x] += (r - l + 1) * delta;
            return;
        }
        pushdown(x, l, r);
        int mid = (l + r) >> 1;
        update(l, mid, x << 1, a, b, delta);
        update(mid + 1, r, x << 1 | 1, a, b, delta);
        tree[x] = tree[x << 1] + tree[x << 1 | 1];
    }
    int query(int l, int r, int x, int a, int b)
    {
        if(l > b || r < a) return 0;
        if(l >= a && r <= b) return tree[x];
        pushdown(x, l, r);
        int mid = (l + r) >> 1;
        return (query(l, mid, x << 1, a, b) + query(mid + 1, r, x << 1 | 1, a, b));
    }
} t;
void dfs(int u, int last)
{
    size[u] = 1;
    for(int i = 0; i < G[u].size(); ++i)
    {
        int v = G[u][i];
        if(v == last) continue;
        dep[v] = dep[u] + 1;
        fa[v] = u;
        dfs(v, u);
        size[u] += size[v];
        if(size[v] > size[son[u]]) son[u] = v;
    }
} 
void dfs(int u, int last, int acs)
{
    dfn[u] = ++cnt;
    top[u] = acs;
    if(son[u]) dfs(son[u], u, acs);
    for(int i = 0; i < G[u].size(); ++i)
    {
        int v = G[u][i];
        if(v == last || v == son[u]) continue;
        dfs(v, u, v);
    }
}
void change(int u)
{
    while(top[u] != 1)
    {
        t.update(1, n, 1, dfn[top[u]], dfn[u], 1);
        u = fa[top[u]];
    }
    t.update(1, n, 1, 1, dfn[u], 1);
}
ll que(int u)
{
    ll ret = 0;
    while(top[u] != 1) 
    {
        ret += t.query(1, n, 1, dfn[top[u]], dfn[u]);
        u = fa[top[u]];
    }
    ret += t.query(1, n, 1, 1, dfn[u]);
    return ret;
}
int main()
{
    scanf("%d%d", &n, &Q);
    for(int i = 2; i <= n; ++i)
    {
        int u;
        scanf("%d", &u);
        ++u;
        G[i].push_back(u);
        G[u].push_back(i);
    }
    for(int i = 1; i <= Q; ++i)
    {
        int l, r, z;
        scanf("%d%d%d", &l, &r, &z);
        ++l;
        ++r;
        ++z;    
        q[++tot].id = i;
        q[tot].p = l - 1;
        q[tot].z = z;
        q[tot].add = -1;
        q[++tot].id = i;
        q[tot].p = r;
        q[tot].z = z;
        q[tot].add = 1;
    }
    dfs(1, 0);
    dfs(1, 0, 1);
    sort(q + 1, q + tot + 1);
    int p = 0;
    while(q[p + 1].p == 0) ++p;
    for(int i = 1; i <= n; ++i)
    {
        change(i);
        while(q[p + 1].p == i) 
        {
            ++p;
            ans[q[p].id] += que(q[p].z) * q[p].add;
        }
    }
    for(int i = 1; i <= Q; ++i)
        printf("%lld\n", (ans[i] % mod + mod) % mod);
    return 0;
}
View Code

 

posted @ 2017-07-26 18:13  19992147  阅读(102)  评论(0编辑  收藏  举报