P4211[BZOJ 3626] [LNOI2014]LCA
题目描述
给出一个n个节点的有根树(编号为0到n-1,根节点为0)。一个点的深度定义为这个节点到根的距离+1。 设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先。 有q次询问,每次询问给出l r z,求 ∑l<=i<=r dep[LCA(i,z)]
输入输出格式
输入格式:
第一行2个整数n q。 接下来n-1行,分别表示点1到点n-1的父节点编号。 接下来q行,每行3个整数l r z。
输出格式:
输出q行,每行表示一个询问的答案。每个答案对201314取模输出
输入输出样例
说明
共5组数据,n与q的规模分别为10000,20000,30000,40000,50000。
题解
话说这题题解基本都是抄清华爷gconeice的吧……实在不会啊……
暴力的想法是,每次把要询问的点向上打上标记,然后让z点向上走,第一个遇到有标记的点就是lca
又因为lca的祖先也有标记,我们可以发现它的深度就是它祖先的标记总数
那么我们可以把每个点到根的路径都+1,然后询问z到根的和,就是答案了
很明显可以用树剖或LCT解决(然而本蒟蒻写不来LCT……)
多组询问如何解决?
我们可以把区间[l,r]的答案拆成[1,r]-[1,l-1]
然后把询问按端点排序,依次向后推,就可以满足条件了……
ps:hzwer大佬强无敌……代码看了我好久才弄明白怎么回事orz
//minamoto
#include<bits/stdc++.h>
#define N 50005
#define mod 201314
using namespace std;
#define getc() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<15,stdin),p1==p2)?EOF:*p1++)
char buf[<<],*p1=buf,*p2=buf;
typedef long long ll;
inline int read(){
#define num ch-'0'
char ch;bool flag=;int res;
while(!isdigit(ch=getc()))
(ch=='-')&&(flag=true);
for(res=num;isdigit(ch=getc());res=res*+num);
(flag)&&(res=-res);
#undef num
return res;
}
int n,m,num,tot;
int sz[N],fa[N],son[N],cnt[N],rk[N],dep[N],top[N];
int ver[N],Next[N],head[N];
int sum[N<<],tag[N<<],l[N<<],r[N<<];
struct que{int z,ans1,ans2;}q[N];
struct data{int num,p;bool flag;}a[N<<];
bool operator <(data a,data b){return a.p<b.p;}
void add(int u,int v){
ver[++tot]=v,Next[tot]=head[u],head[u]=tot;
}
void dfs1(int u){
sz[u]=;dep[u]=dep[fa[u]]+;
for(int i=head[u];i;i=Next[i]){
if(ver[i]==fa[u]) continue;
int v=ver[i];
fa[v]=u;
dfs1(v);
sz[u]+=sz[v];
if(!son[u]||sz[v]>sz[son[u]]) son[u]=v;
}
}
void dfs2(int u){
if(top[u]==-) top[u]=u;
cnt[u]=++num,rk[num]=u;
if(son[u]) top[son[u]]=top[u],dfs2(son[u]);
for(int i=head[u];i;i=Next[i]){
int v=ver[i];
if(v!=fa[u]&&v!=son[u]) dfs2(v);
}
}
void pushdown(int p){
if(tag[p]){
int lc=p<<,rc=p<<|;
sum[lc]+=tag[p]*(r[lc]-l[lc]+);
sum[rc]+=tag[p]*(r[rc]-l[rc]+);
tag[lc]+=tag[p];
tag[rc]+=tag[p];
tag[p]=;
}
}
void build(int p,int ll,int rr){
l[p]=ll,r[p]=rr;
if(ll==rr) return;
int mid=(ll+rr)>>;
build(p<<,ll,mid);
build(p<<|,mid+,rr);
}
void update(int p,int ll,int rr)
{
if(ll<=l[p]&&rr>=r[p])
{
sum[p]+=r[p]-l[p]+;
++tag[p];
return;
}
pushdown(p);
int mid=(l[p]+r[p])>>;
if(ll<=mid) update(p<<,ll,rr);
if(rr>mid) update((p<<)+,ll,rr);
sum[p]=sum[p<<]+sum[p<<|];
}
void solve_update(int x,int f){
while(top[x]!=top[f]){
update(,cnt[top[x]],cnt[x]);
x=fa[top[x]];
}
update(,cnt[f],cnt[x]);
}
int query(int p,int ll,int rr)
{
if(ll<=l[p]&&rr>=r[p]) return sum[p];
pushdown(p);
int mid=(l[p]+r[p])>>;
int val=;
if(ll<=mid) val+=query(p<<,ll,rr);
if(rr>mid) val+=query((p<<)+,ll,rr);
return val;
}
int solve_query(int x,int f){
int sum=;
while(top[x]!=top[f]){
sum+=query(,cnt[top[x]],cnt[x]);
sum%=mod;
x=fa[top[x]];
}
sum+=query(,cnt[f],cnt[x]);sum%=mod;
return sum;
}
int main(){
//freopen("testdata.in","r",stdin);
n=read(),m=read();
memset(top,-,sizeof(top));
for(int i=;i<n;++i){
int x=read();add(x,i);
}
int tot=;
for(int i=;i<=m;++i){
int l=read(),r=read();
q[i].z=read();
a[++tot].p=l-,a[tot].num=i,a[tot].flag=;
a[++tot].p=r,a[tot].num=i,a[tot].flag=;
}
build(,,n);
sort(a+,a++tot);
dfs1(),dfs2();
int now=-;
for(int i=;i<=tot;++i){
while(now<a[i].p){
++now;
solve_update(now,);
}
int t=a[i].num;
if(!a[i].flag) q[t].ans1=solve_query(q[t].z,);
else q[t].ans2=solve_query(q[t].z,);
}
for(int i=;i<=m;++i)
printf("%d\n",(q[i].ans2-q[i].ans1+mod)%mod);
return ;
}
P4211[BZOJ 3626] [LNOI2014]LCA的更多相关文章
- BZOJ 3626: [LNOI2014]LCA [树链剖分 离线|主席树]
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 2050 Solved: 817[Submit][Status ...
- bzoj 3626 [LNOI2014]LCA(离线处理+树链剖分,线段树)
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 1272 Solved: 451[Submit][Status ...
- bzoj 3626: [LNOI2014]LCA 离线+树链剖分
3626: [LNOI2014]LCA Time Limit: 10 Sec Memory Limit: 128 MBSubmit: 426 Solved: 124[Submit][Status] ...
- BZOJ 3626: [LNOI2014]LCA( 树链剖分 + 离线 )
说多了都是泪啊...调了这么久.. 离线可以搞 , 树链剖分就OK了... -------------------------------------------------------------- ...
- [BZOJ 3626] [LNOI2014] LCA 【树链剖分 + 离线 + 差分询问】
题目链接: BZOJ - 3626 题目分析 考虑这样的等价问题,如果我们把一个点 x 到 Root 的路径上每个点的权值赋为 1 ,其余点的权值为 0,那么从 LCA(x, y) 的 Depth 就 ...
- BZOJ 3626 [LNOI2014]LCA:树剖 + 差分 + 离线【将深度转化成点权之和】
题目链接:http://www.lydsy.com/JudgeOnline/problem.php?id=3626 题意: 给出一个n个节点的有根树(编号为0到n-1,根节点为0,n <= 50 ...
- BZOJ 3626 [LNOI2014]LCA 树剖+(离线+线段树 // 在线+主席树)
BZOJ 4012 [HNOI2015]开店 的弱化版,离线了,而且没有边权(长度). 两种做法 1 树剖+离线+线段树 这道题求的是一个点zzz与[l,r][l,r][l,r]内所有点的lcalca ...
- bzoj 3626: [LNOI2014]LCA
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
- bzoj 3626 : [LNOI2014]LCA (树链剖分+线段树)
Description 给出一个n个节点的有根树(编号为0到n-1,根节点为0).一个点的深度定义为这个节点到根的距离+1.设dep[i]表示点i的深度,LCA(i,j)表示i与j的最近公共祖先.有q ...
随机推荐
- 使用Visual Studio进行 Android开发的十大理由
[原文发表地址]Top 10 reasons to use Visual Studio for C++ Android Development! Visual Studio: C++跨平台的移动解决方 ...
- springmvc 类型转换器 数据回显及提示信息
处理器的写法: 类型转换器的写法: 类型转换器在springmvc.xml中的配置如下: index.jsp的写法:
- linux 正则表达式
redis-cli INFO|tr -d '\r'|egrep -v '^(#.*)?$'|sed -E 's/^([^:]*):(.*)$/redisInfo[\1]="\2"/ ...
- JavaScript中call,apply,bind方法
why?call,apply,bind干什么的?为什么要学这个? 一般用来指定this的环境,在没有学之前,通常会有这些问题. var a = { user:"追梦子", fn:f ...
- 【poj3254】Corn Fields 状态压缩dp
AC通道:http://vjudge.net/problem/POJ-3254 [题目大意] 农夫约翰购买了一处肥沃的矩形牧场,分成M*N(1<=M<=12; 1<=N<=12 ...
- mac下yii安装
下载https://github.com/yiisoft/yii2-app-advanced/releases,里边没index.php文件 1.http://www.yiichina.com/que ...
- Cplus Overolad new and delete Operator
思考:在C++类中,通过设计类的构造和析构函数,就已经把复杂的内存管理起来了. 及时是简单的结构体,也是有构造和析构函数的,而下面这种情况,可以在非结构中使用. /** Operator Overlo ...
- Sprint boot notes
1. spring.io 官网 2. http://javainuse.com/spring/sprboot spring boot学习资源 3. spring boot websocketss视频 ...
- sql判断表是否已经存在
if (object_id(N'td_VipExchangeCodeInfo',N'U') is not null)print '存在'else print '不存在'
- 让Asp.Net WebAPI支持OData查询,排序,过滤。(转)
出处:http://www.cnblogs.com/liuzhendong/p/4233380.html 让Asp.Net WebAPI支持OData后,就能支持在url中直接输入排序,过滤条件了. ...