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 ...
随机推荐
- 将bmp文件转换为jpg文件
procedure TForm1.Button1Click(Sender: TObject);(*压缩MBP为JPEG;但是没有提供压缩比可选项凑合用吧,大概1/3 ^_^:Note:必须加上JPEG ...
- Mybatis之XML使用Enum枚举传递数据
在Mybatis中,处理枚举类的TypeHandler有两个: EnumTypeHandler: 用于保存枚举名 EnumOrdinalTypeHandler: 用于保存枚举的序号. 在实际项目中,以 ...
- consul service
{ "name": "consul-agent (host:{{ .MONITOR_CONSUL }})", "command&q ...
- 并发之CAS无锁技术
CAS算法即是:Compare And Swap,比较并且替换: CAS算法存在着三个参数,内存值V,旧的预期值A,以及要更新的值B.当且仅当内存值V和预期值B相等的时候,才会将内存值 ...
- Qt Application Menu In Window and Mac
Application Menu Application menu in different operator systems has different designed style. like W ...
- [Training Video - 1] [Introduction to Web services]
What is a web service? http://webservicex.net/ws/default.aspx WebService是一种跨编程语言和跨操作系统平台的远程调用技术. 跨编程 ...
- 详解jQuery的$符号和init函数
本文所有代码,出自jQuery.1.5.2,为方便理解,引入类的概念,虽然jQuery不是基于面向对象思想. jQuery是现在最流行的JavaScript框架, $是其中最常见的符号,已经在jQue ...
- ACTIVITI 5.14事件监听器的BUG
在ACTIVITI 5.14中,测试内部子流程时发现事件定义的事件监听器不能触发. <activiti:executionListener event="start" del ...
- mongoTemplate更新一个Document里面的数组的一个记录。
假如有一个Document如下: { "_id" : "69bca85a-5a61-4b04-81fb-ff6a71c3802a", "_class& ...
- RocketMQ 运维指令
1.1. 控制台使用 RocketMQ 提供有控制台及一系列控制台命令,用于管理员对主题,集群,broker 等信息的管理 登录控制台 首先进入RocketMQ 工程,进入/RocketMQ/bin ...