P4211 [LNOI2014]LCA

Problem

给一棵\(n\)个节点的有根树,\(m\)次询问,每次询问给\(l,r,z\),求\(\sum_{i = l}^r dep[LCA(i,z)]\)
\(1 \le n,m \le 500000\)

Solution

Thinking 1

我会暴力!
树剖LCA,\(\mathcal{O}(n\log{n} + nq)\)属于是。
你要树剖LCA不会只会倍增的话那还得加个\(\log{n}\cdot q\)

Thinking 2

我会找性质!
发现对于任意两点\(x,y\),询问\(dep[LCA(x,y)]\)其实就是等同于:
在根节点到\(x\)的链上加1
\(y\)到根节点的和
那么对于多组询问\(x \in [l,r]\),我们可以把\(l \sim r\)的所有点到根节点都先加1,然后从\(z\)到根跑一遍即得\(\sum_{i = l} ^ r dep[LCA(i,z)]\)
树剖搞搞就行。

Thinking 3

我是离线人!
把所有询问\(\{l,r,z\}\)拆成\(\{l - 1,z,-1\}\)\(\{r,z,1\}\)
然后按照首排序。
我们把所有点到根节点顺着加一遍,然后中间询问处理一下。这样复杂度非常优秀!

# include <bits/stdc++.h>
using namespace std;
const int N = 5e4 + 5,mod = 201314;
int n,m;
vector <int> g[N];
int f[N],dep[N];
int dfn[N],siz[N],top[N],son[N],dfntot = 0;
int Ans[N];
struct node
{
    int val,lazy;
}T[N << 2];
struct Query
{
    int x,z,opt;
    int answer,id;
    Query() {}
    Query(int _x,int _z,int _opt,int _id) : x(_x),z(_z),opt(_opt),id(_id) {}
}Q[N << 1];
bool compare(const struct Query &x, const struct Query &y)
{
    return x.x < y.x;
}
int Hash[N][2];
void dfs1(int x)
{
    siz[x] = 1;
    for(int i = 0; i < (int)g[x].size(); i++)
    {
        int v = g[x][i];
        if(!dep[v]) 
        {
            dep[v] = dep[x] + 1;
            f[v] = x;
            dfs1(v);
            siz[x] += siz[v];
            if(siz[v] > siz[son[x]]) son[x] = v;
        }
    }
    return;
}  
void dfs2(int x,int _top)
{
    top[x] = _top;
    dfn[x] = ++dfntot;
    if(son[x]) dfs2(son[x],_top);
    for(int i = 0; i < (int)g[x].size(); i++)
    {
        int v = g[x][i];
        if(v != f[x] && v != son[x]) 
        {
            dfs2(v,v);
        }
    }
    return;
}
void pushdown(int root,int l,int r)
{
    if(T[root].lazy == 0) return;
    int tag = T[root].lazy,mid = (l + r) >> 1;
    T[root << 1].val = (T[root << 1].val + tag * (mid - l + 1)) % mod;
    T[root << 1 | 1].val = (T[root << 1 | 1].val + tag * (r - mid)) % mod;
    T[root << 1].lazy = (T[root << 1].lazy + tag) % mod;
    T[root << 1 | 1].lazy = (T[root << 1 | 1].lazy + tag) % mod;
    T[root].lazy = 0;
    return;
}
void update(int root,int l,int r,int s,int t,int d)
{
    if(l <= s && t <= r)
    {
        T[root].val = (T[root].val + d * (t - s + 1)) % mod;
        T[root].lazy = (T[root].lazy + d) % mod;
        return;
    }
    pushdown(root,s,t);
    int mid = (s + t) >> 1;
    if(l <= mid) update(root << 1,l,r,s,mid,d);
    if(r > mid) update(root << 1 | 1,l,r,mid + 1,t,d);
    T[root].val = (T[root << 1].val + T[root << 1 | 1].val) % mod;
    return;
}
int query(int root,int l,int r,int s,int t)
{
    if(l <= s && t <= r) return T[root].val % mod;
    pushdown(root,s,t);
    int mid = (s + t) >> 1;
    int ans = 0;
    if(l <= mid) ans = (ans + query(root << 1,l,r,s,mid)) % mod;
    if(r > mid) ans = (ans + query(root << 1 | 1,l,r,mid + 1,t)) % mod;
    return ans % mod;
}
void modify(int x,int y,int d = 1) // add link(x,y) to 1
{
    while(top[x] != top[y])
    {
        if(dep[top[x]] > dep[top[y]])
            swap(x,y);
        update(1,dfn[top[y]],dfn[y],1,dfntot,d);
        y = f[top[y]];
    }
    if(dep[x] > dep[y]) swap(x,y);
    update(1,dfn[x],dfn[y],1,dfntot,d);
    return;
}
int q(int x,int y)
{
    int ans = 0;
    while(dep[top[x]] != dep[top[y]])
    {
        if(dep[top[x]] > dep[top[y]]) 
            swap(x,y);
        ans = (ans + query(1,dfn[top[y]],dfn[y],1,dfntot)) % mod;
        y = f[top[y]];
    }
    if(dep[x] > dep[y]) swap(x,y);
    ans = (ans + query(1,dfn[x],dfn[y],1,dfntot)) % mod;
    return ans;
}
int main(void)
{
    scanf("%d%d",&n,&m);
    for(int i = 2; i <= n; i++)
    {
        int v; scanf("%d",&v);
        ++v;
        g[i].push_back(v),g[v].push_back(i);
    }
    dep[1] = 1;
    dfs1(1),dfs2(1,1);
    for(int i = 1; i <= m; i++)
    {
        int l,r,z; scanf("%d%d%d",&l,&r,&z); ++l,++r,++z;
        Q[i * 2 - 1] = Query(l - 1,z,-1,i);
        Q[i * 2] = Query(r,z,1,i);
        Hash[l - 1][0] = i * 2 - 1,Hash[r][1] = i * 2;
    }
    sort(Q + 1, Q + 2 * m + 1, compare);
    for(int i = 1,j = 1; i <= 2 * m; i++)
    {
        while(j <= n && j <= Q[i].x)
        {
            modify(1,j);
            ++j;
        }
        Q[i].answer = q(1,Q[i].z);
        // printf("i = %d,x = %d,z = %d,answer = %d\n",i,Q[i].x,Q[i].z,Q[i].answer);
    }
    for(int i = 1; i <= 2 * m; i++)
    {
        Ans[Q[i].id] = (Ans[Q[i].id] + Q[i].opt * Q[i].answer + mod) % mod;
    }
    for(int i = 1; i <= m; i++) printf("%d\n",Ans[i]);
    return 0;
}
posted @ 2021-08-07 18:13  luyiming123  阅读(28)  评论(0编辑  收藏  举报