题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626

题意:

  给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50000)。

  一个点的深度定义为这个节点到根的距离+1。

  设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。

  有q次询问,每次询问给出l,r,z,求∑ dep[LCA(i,z)] (l<=i<=r)。

  (即,求在[l,r]区间内的每个节点i与z的最近公共祖先的深度之和)

题解:

  假设有一棵所有点都为0的树。

  如果将x到root路径上的点都+1,则dep[LCA(x,y)] = y到root路径上的点权之和,且这个操作具有叠加性。(树剖)

  所以对于询问query(l to r) = query(r) - query(l-1)。(差分)

  显然,只需要求出在询问中有的l和r的query。

  所以依次枚举节点i = 0 to n-1,将i到root的路径+1,如果i是某一些询问的l或r,则记录相应的query(z)。(离线)

  总复杂度O((n+q)*logn*logn)

AC Code:

 #include <iostream>
#include <stdio.h>
#include <string.h>
#include <vector>
#define MAX_N 200005
#define MAX_M 50005
#define MOD 201314 using namespace std; struct Query
{
int ver;
int id;
int dr;
Query(int _ver,int _id,int _dr)
{
ver=_ver;
id=_id;
dr=_dr;
}
Query(){};
}; int n,m;
int tot=;
int cnt=;
int l[MAX_M];
int r[MAX_M];
int z[MAX_M];
int dat[MAX_N];
int lazy[MAX_N];
int lson[MAX_N];
int rson[MAX_N];
int par[MAX_N];
int dep[MAX_N];
int siz[MAX_N];
int tp[MAX_N];
int son[MAX_N];
int dfsx[MAX_N];
int ans[MAX_M][];
vector<int> edge[MAX_N];
vector<Query> q[MAX_M]; inline int mod(int x)
{
return (x%MOD+MOD)%MOD;
} int build(int l,int r)
{
int rt=++tot;
dat[rt]=lazy[rt]=;
lson[rt]=rson[rt]=;
if(l<r)
{
int mid=(l+r)>>;
lson[rt]=build(l,mid);
rson[rt]=build(mid+,r);
}
return rt;
} void push_down(int k,int len)
{
if(lazy[k])
{
if(lson[k])
{
dat[lson[k]]=mod(dat[lson[k]]+lazy[k]*(len-(len>>)));
lazy[lson[k]]=mod(lazy[lson[k]]+lazy[k]);
}
if(rson[k])
{
dat[rson[k]]=mod(dat[rson[k]]+lazy[k]*(len>>));
lazy[rson[k]]=mod(lazy[rson[k]]+lazy[k]);
}
lazy[k]=;
}
} void push_up(int k)
{
dat[k]=;
if(lson[k]) dat[k]=mod(dat[k]+dat[lson[k]]);
if(rson[k]) dat[k]=mod(dat[k]+dat[rson[k]]);
} void update(int a,int b,int k,int l,int r,int x)
{
if(a<=l && r<=b)
{
dat[k]=mod(dat[k]+(r-l+)*x);
lazy[k]=mod(lazy[k]+x);
return;
}
if(r<a || b<l) return;
push_down(k,r-l+);
int mid=(l+r)>>;
update(a,b,lson[k],l,mid,x);
update(a,b,rson[k],mid+,r,x);
push_up(k);
} int query(int a,int b,int k,int l,int r)
{
if(a<=l && r<=b) return dat[k];
if(r<a || b<l) return ;
push_down(k,r-l+);
int mid=(l+r)>>;
int v1=query(a,b,lson[k],l,mid);
int v2=query(a,b,rson[k],mid+,r);
return mod(v1+v2);
} void dfs1(int now,int d)
{
dep[now]=d;
siz[now]=;
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if(temp!=par[now])
{
dfs1(temp,d+);
siz[now]+=siz[temp];
}
}
} void dfs2(int now,int anc)
{
tp[now]=anc;
son[now]=-;
dfsx[now]=++cnt;
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if((son[now]==- || siz[temp]>siz[son[now]]) && temp!=par[now])
{
son[now]=temp;
}
}
if(son[now]!=-) dfs2(son[now],anc);
for(int i=;i<edge[now].size();i++)
{
int temp=edge[now][i];
if(temp!=par[now] && temp!=son[now]) dfs2(temp,temp);
}
} void update_chain(int a,int x)
{
while(tp[a]!=)
{
update(dfsx[tp[a]],dfsx[a],,,n,x);
a=par[tp[a]];
}
update(,dfsx[a],,,n,x);
} int query_chain(int a)
{
int sum=;
while(tp[a]!=)
{
sum=mod(sum+query(dfsx[tp[a]],dfsx[a],,,n));
a=par[tp[a]];
}
sum=mod(sum+query(,dfsx[a],,,n));
return sum;
} void read()
{
scanf("%d%d",&n,&m);
for(int i=;i<n;i++)
{
scanf("%d",&par[i]);
edge[i].push_back(par[i]);
edge[par[i]].push_back(i);
}
} void solve()
{
build(,n);
dfs1(,);
dfs2(,);
for(int i=;i<m;i++)
{
scanf("%d%d%d",&l[i],&r[i],&z[i]);
if(l[i]>) q[l[i]-].push_back(Query(z[i],i,));
q[r[i]].push_back(Query(z[i],i,));
}
memset(ans,,sizeof(ans));
for(int i=;i<n;i++)
{
update_chain(i,);
for(int j=;j<q[i].size();j++)
{
Query temp=q[i][j];
ans[temp.id][temp.dr]=query_chain(temp.ver);
}
}
} void print()
{
for(int i=;i<m;i++)
{
printf("%d\n",mod(ans[i][]-ans[i][]));
}
} int main()
{
read();
solve();
print();
}

BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】的更多相关文章

  1. BZOJ 3626: [LNOI2014]LCA(树剖+差分+线段树)

    传送门 解题思路 比较有意思的一道题.首先要把求\(\sum\limits_{i=l}^r dep[lca(i,z)]\)这个公式变一下.就是考虑每一个点的贡献,做出贡献的点一定在\(z\)到根节点的 ...

  2. BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2050  Solved: 817[Submit][Status ...

  3. BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )

    说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...

  4. BZOJ 3626 [LNOI2014]LCA 树剖+(离线+线段树 // 在线+主席树)

    BZOJ 4012 [HNOI2015]开店 的弱化版,离线了,而且没有边权(长度). 两种做法 1 树剖+离线+线段树 这道题求的是一个点zzz与[l,r][l,r][l,r]内所有点的lcalca ...

  5. BZOJ 3626: [LNOI2014]LCA 树链剖分 线段树 离线

    http://www.lydsy.com/JudgeOnline/problem.php?id=3626 LNOI的树链剖分题没有HAOI那么水,学到的东西还是很多的. 我如果现场写,很难想出来这种题 ...

  6. bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)

    Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...

  7. BZOJ 3626 [LNOI2014]LCA ——树链剖分

    思路转化很巧妙. 首先把询问做差分. 然后发现加入一个点就把路径上的点都+1,询问的时候直接询问到根的路径和. 这样和原问题是等价的,然后树链剖分+线段树就可以做了. #include <map ...

  8. bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 1272  Solved: 451[Submit][Status ...

  9. bzoj 3626: [LNOI2014]LCA 离线+树链剖分

    3626: [LNOI2014]LCA Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 426  Solved: 124[Submit][Status] ...

随机推荐

  1. APICloud打包Vue单页应用

    APICloud新建项目后,会生成以下目录结构 其中index.html是入口文件,而vue-cli打包生成的文件是在dist目录下 ├─dist│ └─static│ ├─css│ └─js │ └ ...

  2. 刷脸支付真的来啦!华为nova3带你玩转酷时代~

    无论是不愿脱离手套的怕冷手. 或是沾满泥土芬芳的勤劳手. 还是挂着水滴的清洁手…… 每当这些时刻,打开支付宝认证支付, 指纹解锁的能力总是光彩尽失. 不过,就在华为nova 3的发布会上, 一项传说已 ...

  3. 使用MongoDB 记录业务日志

    最近公司有个需求,要对业务日志进行记录并根据日志排查问题,以前都是使用log4net之类的日志组件来记录到文件,这种方式已经不能满足业务的需要,因为日志文件会很大,即使进行分割后,查找也是很不方便,何 ...

  4. 解决ajax跨域问题的多种方法

    //第一种方法使用jsonp的方式 <script type="text/javascript" src="http://www.youxiaju.com/js/j ...

  5. hdu 5285 wyh2000 and pupil(二染色)

    第一次用vector解得题.值得纪念,这道题是二染色问题,我用bfs解得.就是染色,推断,计数问题,其 实挺简单的,就是得判一下特殊情况,当n<2的时候就不能有解,由于题目要求每一个组至少有一个 ...

  6. swift中的?和!理解

    本文转载至 http://www.cnblogs.com/dugulong/p/3770367.html 首先贴cocoachina上某位大大的帖子:     Swift语言使用var定义变量,但和别 ...

  7. 【BZOJ2728】[HNOI2012]与非 并查集+数位DP

    [BZOJ2728][HNOI2012]与非 Description Input 输入文件第一行是用空格隔开的四个正整数N,K,L和R,接下来的一行是N个非负整数A1,A2……AN,其含义如上所述.  ...

  8. Residual (numerical analysis)

    In many cases, the smallness of the residual means that the approximation is close to the solution, ...

  9. 20179209《Linux内核原理与分析》第十二周作

    缓冲区溢出漏洞实验 缓冲区溢出简介 缓冲区溢出是指程序试图向缓冲区写入超出预分配固定长度数据的情况.这一漏洞可以被恶意用户利用来改变程序的流控制,甚至执行代码的任意片段.这一漏洞的出现是由于数据缓冲器 ...

  10. java_Ninja实战过程

    使用Ninja马上两年了,之前多多少少的都是跟着项目模仿着写,今年上半年准备从一个小项目开始从始至终走一遍; 首先官网:http://www.ninjaframework.org; github: h ...