• [LNOI2014]LCA


    [LNOI2014]LCA

    题目

    给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。
    设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。
    有q次询问,每次询问给出l r z,求sigma_{l<=i<=r}dep[LCA(i,z)]。
    (即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

    INPUT

    第一行2个整数n q。
    接下来n-1行,分别表示点1到点n-1的父节点编号。
    接下来q行,每行3个整数l r z。

    OUTPUT

    输出q行,每行表示一个询问的答案。每个答案对201314取模

    SAMPLE

    INPUT

    5 2
    0
    0
    1
    1
    1 4 3
    1 4 2

    OUTPUT

    8

    5

    解题报告

    首先提出一个结论

    $x$点与$y$点的$LCA$可以由如下方式求得:

    将$x$点到根路径上所有点点权置为$1$,其余点点权置为$0$,则$y$点到根路径上点权和即为所求

    原因很简单,手画一下就可以发现这个规律

    有了这个结论,我们就可以把求$LCA$这种操作转化为路径上的点权操作了,也就是说,树链剖分就可行了起来

    我们考虑如何处理一段区间的贡献,显然可以用差分来搞,那么我们就可以将操作离线,将询问拆成两个,进行差分,扫一遍节点,进行点权覆盖与差分查询即可

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cstdio>
     4 #include <vector>
     5 using namespace std;
     6 inline int read(){
     7     int sum(0);char ch(getchar());
     8     for(;ch<'0'||ch>'9';ch=getchar());
     9     for(;ch>='0'&&ch<='9';sum=sum*10+(ch^48),ch=getchar());
    10     return sum;
    11 }
    12 const int mod(201314);
    13 struct edge{int e;edge *n;}*pre[50005];
    14 inline void insert(int s,int e){edge *tmp(new edge);tmp->e=e;tmp->n=pre[s];pre[s]=tmp;}
    15 int n,q;
    16 int z[50005];
    17 vector<int>sub[50005],add[50005];
    18 int sum[200005],lazy[200005];
    19 inline void pushup(int i){sum[i]=(sum[i<<1]+sum[i<<1|1])%mod;}
    20 inline void pushdown(int i,int len){
    21     if(lazy[i]){
    22         lazy[i<<1]=(lazy[i<<1]+lazy[i])%mod;
    23         lazy[i<<1|1]=(lazy[i<<1|1]+lazy[i])%mod;
    24         sum[i<<1]=(sum[i<<1]+lazy[i]*(len-(len>>1))%mod)%mod;
    25         sum[i<<1|1]=(sum[i<<1|1]+lazy[i]*(len>>1)%mod)%mod;
    26         lazy[i]=0;
    27     }
    28 }
    29 inline void update(int ll,int rr,int w,int l,int r,int i){
    30     if(ll<=l&&r<=rr){lazy[i]=(lazy[i]+w)%mod;sum[i]=(sum[i]+w*(r-l+1)%mod)%mod;return;}
    31     int mid((l+r)>>1);pushdown(i,r-l+1);
    32     if(ll<=mid)update(ll,rr,w,l,mid,i<<1);if(mid<rr)update(ll,rr,w,mid+1,r,i<<1|1);pushup(i);
    33 }
    34 inline int query(int ll,int rr,int l,int r,int i){
    35     if(ll<=l&&r<=rr)return sum[i];int ret(0),mid((l+r)>>1);pushdown(i,r-l+1);
    36     if(ll<=mid)ret=query(ll,rr,l,mid,i<<1);if(mid<rr)ret=(ret+query(ll,rr,mid+1,r,i<<1|1))%mod;return ret;
    37 }
    38 int ans[50005];
    39 int fa[50005],son[50005],size[50005],dep[50005];
    40 inline void dfs1(int u){
    41     son[u]=0;size[u]=1;
    42     for(edge *i=pre[u];i;i=i->n){
    43         int e(i->e);dep[e]=dep[u]+1;dfs1(e);
    44         size[u]+=size[e];if(size[e]>size[son[u]])son[u]=e;
    45     }
    46 }
    47 int cnt,id[50005],pos[50005],top[50005];
    48 inline void dfs2(int u,int rt){
    49     top[u]=rt;id[u]=++cnt;pos[cnt]=u;if(son[u])dfs2(son[u],rt);
    50     for(edge *i=pre[u];i;i=i->n){int e(i->e);if(e==son[u])continue;dfs2(e,e);}
    51 }
    52 inline void change(int x,int y){
    53     while(top[x]^top[y]){
    54         if(dep[top[x]]<dep[top[y]])swap(x,y);
    55         update(id[top[x]],id[x],1,1,n,1);
    56         x=fa[top[x]];
    57     }
    58     if(dep[x]>dep[y])swap(x,y);
    59     update(id[x],id[y],1,1,n,1);
    60 }
    61 inline int ask(int x,int y){
    62     int ret(0);
    63     while(top[x]^top[y]){
    64         if(dep[top[x]]<dep[top[y]])swap(x,y);
    65         ret=(ret+query(id[top[x]],id[x],1,n,1))%mod;
    66         x=fa[top[x]];
    67     }
    68     if(dep[x]>dep[y])swap(x,y);
    69     ret=(ret+query(id[x],id[y],1,n,1))%mod;
    70     return ret;
    71 }
    72 int main(){
    73     n=read();q=read();
    74     for(int i=2;i<=n;++i){
    75         int x(read()+1);fa[i]=x;insert(x,i);
    76     }
    77     for(int i=1;i<=q;++i){
    78         int x(read()+1),y(read()+1);z[i]=read()+1;
    79         sub[x-1].push_back(i);add[y].push_back(i);
    80     }
    81     dfs1(1);dfs2(1,1);
    82     for(int i=1;i<=n;++i){
    83         change(i,1);
    84         for(int j=0,k=sub[i].size();j<k;++j)
    85             ans[sub[i][j]]=((ans[sub[i][j]]-ask(z[sub[i][j]],1))%mod+mod)%mod;
    86         for(int j=0,k=add[i].size();j<k;++j)
    87             ans[add[i][j]]=(ans[add[i][j]]+ask(z[add[i][j]],1))%mod;
    88     }
    89     for(int i=1;i<=q;++i)printf("%d
    ",ans[i]);
    90 }
    View Code
  • 相关阅读:
    matlab函数集锦
    视觉(1)[导入]EStereo
    我为啥申请这里的博客?
    [导入]给定一个英文原文,统计文件里面一共有多少个不同的英文单词
    视觉(2)[导入]opengl贴图程序
    C++ Builder 控件的卸载<转载>
    [转]<不知道能否解决先转下来再说>不显示删除回复显示所有回复显示星级回复显示得分回复 没有找到MSVR90D.dll因此这个应用程序未能启动
    终于把《windows程序设计》上册读完了,hoho
    乱思。。。。。。。、、、、、
    测试windows live writer
  • 原文地址:https://www.cnblogs.com/hzoi-mafia/p/7780613.html
Copyright © 2020-2023  润新知