[LNOI2014]LCA

旧城冷巷雨未停 提交于 2019-12-02 08:46:48

[LNOI2014]LCA
这道题难道不是数据结构水题吗 逃)
首先想到一个i点的\(dep\)相当于根节点走到i 进过的点之和,所以这个点对答案的贡献就是从这个点走到根节点。因此我们可以转换为当前节点\(i\)到根节点所经过的所有节点权值++。
显然可以用线段树+树链剖分的数据结构进行优化 对于每一个询问 建一颗权值线段树 存储当前区间\(sum\),\(sum\)存储的就是\(sum\)
然后我们需要想到用 类似于前缀和的思想来进行优化
例如 \(l=2 ,r=4 ,z=4\) 我们可以用前缀和的思想进行优化 计算\(1到4\)\(sum\)\(-1到1的sum\) 就可以得到答案了
想到了前缀和 想到了树剖+线段树 如果每一次查询 你都要新建两次树
那就会GG!
因此我们又想到了莫队的思想,将询问区间的\(l,r\)排序(因为询问区间为\(1到l\)\(1到r\),左区间都是一样的,所以我们可以将l,r一起排序),然后一个一个的加点 这样就可以不用每一次询问都新建一颗树了

#include <cstdio>
#include <iostream>
#include <algorithm>
#include <cstring>
#define int long long 
using namespace std;
const int mod=201314,maxn=100010;
int n,q,tot,fa[maxn],cnt_q;
int first[maxn],nxt[maxn<<1],to[maxn<<1],dep[maxn<<1],cnt_id;
int id[maxn<<1],rk[maxn<<1],size[maxn<<1],son[maxn<<1],top[maxn<<1],now;
int tag[maxn<<1],sum[maxn<<1];
struct node{
    int id,pos,z,flag;
    inline bool operator <(const node &x)const{
        return pos<x.pos || (x.pos==pos && id<x.id);
    }
}ques[maxn<<4];
struct node1{
    int ans1,ans2;
}ans[maxn<<2];
void dfs1(int x,int father){
    size[x]=1;fa[x]=father;
    for(int i=first[x];i;i=nxt[i]){
        int y=to[i];if(y==father) continue;
        dep[y]=dep[x]+1;
        dfs1(y,x);size[x]+=size[y];
        if(size[son[x]]<size[y])
            son[x]=y;
    }
}
void dfs2(int x,int topo){
    id[x]=++cnt_id;rk[cnt_id]=x;top[x]=topo;
    if(son[x])  dfs2(son[x],topo);
    for(int i=first[x];i;i=nxt[i]){
        int y=to[i];if(y==fa[y] || y==son[x]) continue;
        dfs2(y,y);
    }
}
void add(int x,int y){nxt[++tot]=first[x];first[x]=tot;to[tot]=y;}
void tagg(int node,int l,int r,int ta)
{
    sum[node]=(sum[node]+(r-l+1)*ta)%mod;
    if(l<r) tag[node]=(tag[node]+ta)%mod;   
}
void push_down(int node,int l,int r){
    if(l<r && tag[node]){
        int mid=(l+r)>>1;
        tagg(node<<1,l,mid,tag[node]);
        tagg(node<<1|1,mid+1,r,tag[node]);
    }
    tag[node]=0;
}
void push_up(int node){sum[node]=(sum[node<<1]+sum[node<<1|1])%mod;}
void modify(int node,int l,int r,int ql,int qr){
    if(qr<l || ql>r) return ;
    if(ql<=l && r<=qr){
        tagg(node,l,r,1);
        return ;
    }
    push_down(node,l,r);
    int mid=(l+r)>>1;
    modify(node<<1,l,mid,ql,qr);modify(node<<1|1,mid+1,r,ql,qr);
    push_up(node);
}
void line_modify(int x,int y){
    int tx=top[x],ty=top[y];
    while(tx!=ty){
        if(dep[tx]<dep[ty]){
            x^=y^=x^=y;tx^=ty^=tx^=ty;
        }
        modify(1,1,n,id[tx],id[x]);
        x=fa[tx];tx=top[x];
    }
    if(dep[x]<dep[y])
        x^=y^=x^=y;
    modify(1,1,n,id[y],id[x]);
}
int query(int node,int l,int r,int ql,int qr){
    if(ql<=l && r<=qr)  return (sum[node]%mod);
    push_down(node,l,r);
    int mid=(l+r)>>1,anss=0;
    if(ql<=mid) anss+=query(node<<1,l,mid,ql,qr);
    if(mid<qr) anss+=query(node<<1|1,mid+1,r,ql,qr);
    return anss%mod;
}
int line_query(int x,int y){
    int tx=top[x],ty=top[y],anss=0;
    while(tx!=ty){
        if(dep[tx]<dep[ty]){
            x^=y^=x^=y;tx^=ty^=tx^=ty;
        }
        anss+=query(1,1,n,id[tx],id[x]);
        anss%=mod;
        x=fa[tx];tx=top[x];
    }
    if(dep[x]<dep[y])
        x^=y^=x^=y;
    anss+=query(1,1,n,id[y],id[x]);
    return anss%mod;
}
signed main(){
    scanf("%lld %lld",&n,&q);
    for(int i=2,x;i<=n;i++){
        scanf("%lld",&x);add(++x,i);
    }
        
    dep[1]=1;
    dfs1(1,0);dfs2(1,1);
    for(int i=1,l,r,z;i<=q;i++){
         scanf("%lld %lld %lld",&l,&r,&z);r++;z++;
         ques[++cnt_q]=((node){i,l,z,0});ques[++cnt_q]=((node){i,r,z,1});
    }
    sort(ques+1,ques+1+cnt_q);now=0;
    for(int i=1;i<=cnt_q;i++){
        while(now<ques[i].pos)
            line_modify(1,++now);
        int num=ques[i].id;
        if(ques[i].flag==1) ans[num].ans1=line_query(1,ques[i].z);
        else ans[num].ans2 =line_query(1,ques[i].z);
    }
    for(int i=1;i<=q;i++)
        printf("%lld\n",(ans[i].ans1-ans[i].ans2+mod)%mod);
    return 0;
}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!