真正的危机不是机器人像人一样思考,而是人像机器一样思考。 ——凉宫春日的忧郁

[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\n",ans[i]);
90 }
View Code

 

posted @ 2017-11-03 21:33  Hzoi_Mafia  阅读(192)  评论(0编辑  收藏  举报
我们都在命运之湖上荡舟划桨,波浪起伏着而我们无法逃脱孤航。但是假使我们迷失了方向,波浪将指引我们穿越另一天的曙光。 ——死神