P4211 [LNOI2014]LCA

又一鬼题
对于每次查询
把l-r到跟的路上+1
然后深度就是这个位置的全职
然后查分一下,查询r-l
这样就可以离线记下查询位置
只添加,不用删除
就可以利用之前的信息了

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#define mid (l+r>>1)
using namespace std;
const int M=2e6+5,p=201314;
int n,m,head[M],tot,cnt,nex[M*2],to[M*2],id[M],size[M],top[M],son[M],f[M],c[M],ans[M],root=1;
vector<int> L[M],R[M];
struct SEG{
    int sum[M],add[M];SEG(){memset(sum,0,sizeof sum);memset(add,0,sizeof add);}
    void update(int o){sum[o]=(sum[o<<1]+sum[o<<1|1])%p;}
    void pushdown(int o,int l,int r){
        if(add[o]){
            add[o<<1]=(add[o]+add[o<<1])%p;add[o<<1|1]=(add[o<<1|1]+add[o])%p;
            sum[o<<1]=(sum[o<<1]+add[o]*(mid-l+1)%p)%p;sum[o<<1|1]=(sum[o<<1|1]+add[o]*(r-mid)%p)%p;
            add[o]=0;
        }
    }
    void modify(int o,int l,int r,int ql,int qr){
        if(l>qr||r<ql) return ;
        if(ql<=l&&r<=qr) {sum[o]=(sum[o]+r-l+1)%p,add[o]=(add[o]+1)%p;return;}
        pushdown(o,l,r);
        modify(o<<1,l,mid,ql,qr);
        modify(o<<1|1,mid+1,r,ql,qr);
        update(o);
    }
    int query(int o,int l,int r,int ql,int qr){
        if(l>qr||r<ql) return 0;
        if(ql<=l&&r<=qr) {return sum[o];}
        pushdown(o,l,r);
        return query(o<<1,l,mid,ql,qr)+query(o<<1|1,mid+1,r,ql,qr);
    }
}T;
void add(int u,int v){
    to[++tot]=v;
    nex[tot]=head[u];
    head[u]=tot;
}
void dfs(int x){ size[x]=1;
    for(int i=head[x],tmp;i;i=nex[i]){
        dfs(tmp=to[i]);size[x]+=size[tmp];
        son[x]=(size[tmp]>size[son[x]])?tmp:son[x];
    }
}
void dfs2(int x,int ff){ 
    id[x]=++cnt;top[x]=ff;
    if(!son[x]) return ;
    dfs2(son[x],ff);
    for(int i=head[x],tmp;i;i=nex[i])
        if(!id[to[i]])dfs2(to[i],to[i]);

}
void modify(int x){
    while(x){
        T.modify(1,1,cnt,id[top[x]],id[x]);
        x=f[top[x]];
    }
}
int query(int x){int ans=0;
    while(x){
        ans=(ans+T.query(1,1,cnt,id[top[x]],id[x]))%p;
        x=f[top[x]];
    }return ans;
}
int main(){
    scanf("%d%d",&n,&m);
    for(int i=2,v;i<=n;i++){
        scanf("%d",&v);v++;
        add(f[i]=v,i);
    }
    dfs(root);dfs2(root,root);
    for(int i=1,l,r;i<=m;i++) {
        scanf("%d%d%d",&l,&r,&c[i]);r++;c[i]++;
        L[l].push_back(i);
        R[r].push_back(i);
    }
    for(int i=1;i<=n;i++){
        modify(i);
        for(int j=0;j<L[i].size();j++) ans[L[i][j]]=(ans[L[i][j]]-query(c[L[i][j]]))%p;
        for(int j=0;j<R[i].size();j++) ans[R[i][j]]=(ans[R[i][j]]+query(c[R[i][j]]))%p;
    }
     for(int i=1;i<=m;i++) printf("%d\n",(ans[i]%p+p)%p);
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值