题目链接: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. centos 6.9使用Rsync+Inotify-tools实现数据实时同步

    centos 6.9使用Rsync+Inotify-tools实现数据实时同步 说明: 操作系统:CentOS 6.9 源服务器:192.168.1.222 备份服务器:192.168.1.1.233 ...

  2. 滑动窗口计数java实现

    滑动窗口计数有很多使用场景,比如说限流防止系统雪崩.相比计数实现,滑动窗口实现会更加平滑,能自动消除毛刺. 概念上可以参考TCP的滑窗算法,可以看一下这篇文章(http://go12345.iteye ...

  3. mysql 不同库不同表字段数据复制

    需求:把一个表某个字段内容复制到另一张表的某个字段. 实现sql语句1: UPDATE file_manager_folder f1 LEFT OUTER JOIN file_manager_fold ...

  4. poj2349

    Arctic Network Time Limit: 2000MS   Memory Limit: 65536K Total Submissions: 0   Accepted: 0 Descript ...

  5. 【BZOJ3316】JC loves Mkk 分数规划+单调队列

    [BZOJ3316]JC loves Mkk Description Input 第1行,包含三个整数.n,L,R.第2行n个数,代表a[1..n]. Output 仅1行,表示询问答案.如果答案是整 ...

  6. Pairs of Integers

    Pairs of Integers You are to find all pairs of integers such that their sum is equal to the given in ...

  7. java高级主题

    1 java.util.concurrent.locks.LockSupport park:阻塞线程. unpark:解除阻塞线程. 线程阻塞最基础的组件. 2 sun.misc.Unsafe 可以用 ...

  8. phpstorm+xdebug, 实现断点调试: xdebug如何配置

    [XDebug] xdebug.profiler_output_dir="D:\phpStudy\tmp\xdebug" xdebug.trace_output_dir=" ...

  9. Js自定义异常

    function MyError(msg){ this.name="MyError"; this.message = msg || "自定义异常的默认消息";} ...

  10. Linux c编程:I/O多路复用之epoll

    前面介绍了select处理,这一章继续介绍另外一种I/O多路服用的机制:epoll.来比较下两种机制的不同点. select: 调用过程如下: (1)使用copy_from_user从用户空间拷贝fd ...