[LNOI2014]LCA

题目描述

给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。

设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求$\sum_{l\leq i \leq r}dep[lca(i,z)]$

题解

总体思路和[GXOI/GZOI2019]旧词一样。甚至这个还简单一点,就是k=1;

只是从[1,r]变成[l,r],其实很简单,稍微差分一下机OK了,可以查询[1,r]和[1,l-1]的答案相减。

根据之前的性质可知是有可减性的。

在记录答案时,为了简单一点,同时利用r>l-1后被查询且最初数组为0的性质,直接将当前查询到的答案与之前记录的相减即可。

//差分性质,对于[l,r]的询问,可以求到[1,l-1]和[1,r]的询问,再相减 
#include<bits/stdc++.h>
using namespace std;
#define ll long long
const int maxn=50005;
const int mod=201314;
int n,m;
int dep[maxn],fa[maxn],size[maxn],son[maxn];
int num,id[maxn],top[maxn];
int root,ls[maxn<<1],rs[maxn<<1],len[maxn<<1];
ll sum[maxn<<1],tag[maxn<<1];
ll get_it[maxn];
vector<int>e[maxn];
vector<pair<int,int> > q[maxn];

template<class T>void read(T &x){
    x=0;char ch=getchar();
    while(!isdigit(ch)) ch=getchar();
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
}

void dfs(int u){
    size[u]=1;
    for(unsigned int i=0;i<e[u].size();i++){
        int v=e[u][i];
        dep[v]=dep[u]+1;
        dfs(v);
        size[u]+=size[v];
        if(size[son[u]]<size[v]) son[u]=v;
    }
}

void dfs(int u,int tp){
    id[u]=++num;
    top[u]=tp;
    if(!son[u]) return ;
    dfs(son[u],tp);
    for(unsigned int i=0;i<e[u].size();i++){
        int v=e[u][i];
        if(v==son[u]) continue;
        dfs(v,v);
    }
}

void build(int &rt,int l,int r){
    rt=++num;
    len[rt]=r-l+1;
    if(l==r) return ;
    int mid=(l+r)>>1;
    build(ls[rt],l,mid);
    build(rs[rt],mid+1,r);
}

void put_tag(int rt,int val){
    tag[rt]=(tag[rt]+val)%mod;
    sum[rt]=(sum[rt]+val*len[rt])%mod;
}

void push_down(int rt){
    put_tag(ls[rt],tag[rt]);
    put_tag(rs[rt],tag[rt]);
    tag[rt]=0;
}

void update(int rt){
    sum[rt]=(sum[ls[rt]]+sum[rs[rt]])%mod;
}

void modify(int rt,int l,int r,int a_l,int a_r){
    if(a_l<=l&&r<=a_r){
        put_tag(rt,1);
        return ;
    }
    if(tag[rt]) push_down(rt);
    int mid=(l+r)>>1;
    if(a_l<=mid) modify(ls[rt],l,mid,a_l,a_r);
    if(mid<a_r) modify(rs[rt],mid+1,r,a_l,a_r);
    update(rt);
}

void modify(int x,int y){
    while(top[x]!=top[y]){
        modify(1,1,n,id[top[y]],id[y]);
        y=fa[top[y]];
    }
    modify(1,1,n,id[x],id[y]);
}

ll query(int rt,int l,int r,int a_l,int a_r){
    if(a_l<=l&&r<=a_r) return sum[rt];
    if(tag[rt]) push_down(rt);
    int mid=(l+r)>>1;
    ll ret=0;
    if(a_l<=mid) ret+=query(ls[rt],l,mid,a_l,a_r);
    if(mid<a_r) ret+=query(rs[rt],mid+1,r,a_l,a_r);
    return ret%mod;
}

ll query(int x,int y){
    ll ret=0;
    while(top[x]!=top[y]){
        ret=(ret+query(1,1,n,id[top[y]],id[y]))%mod;
        y=fa[top[y]];
    }
    ret=(ret+query(1,1,n,id[x],id[y]))%mod;
    return ret;
}

int main(){
    read(n);read(m);
    for(int i=2;i<=n;i++){
        read(fa[i]);
        fa[i]++;
        e[fa[i]].push_back(i);
    }
    for(int i=1;i<=m;i++){
        int x,y,z;
        read(x);read(y);read(z);
        x++;y++;z++;
        q[x-1].push_back(make_pair(z,i));
        q[y].push_back(make_pair(z,i));
    }
    dfs(1);
    dfs(1,1);
    num=0;
    build(root,1,n);
    for(int i=1;i<=n;i++){
        modify(1,i);
        for(unsigned int j=0;j<q[i].size();j++){
            ll x=query(1,q[i][j].first);
            get_it[q[i][j].second]=((x-get_it[q[i][j].second])%mod+mod)%mod;
        }
    }
    for(int i=1;i<=m;i++) printf("%lld\n",get_it[i]);
}
View Code
posted @ 2019-07-25 21:24  _JSQ  阅读(280)  评论(0编辑  收藏  举报