【CF725G】Messages on a Tree 树链剖分+线段树
【CF725G】Messages on a Tree
题意:给你一棵n+1个节点的树,0号节点是树根,在编号为1到n的节点上各有一只跳蚤,0号节点是跳蚤国王。现在一些跳蚤要给跳蚤国王发信息。具体的信息传输过程如下:
1.信息的发起者把信息上传给他父亲节点处的跳蚤,然后自身进入等待状态。
3.跳蚤国王在收到信息时会将信息立刻下传到发来信息的那个儿子,跳蚤国王可以在同一时刻下传多份信息。
4.上传:a把信息传给b。如果b正处于等待状态,则b会立刻将a发来的信息下传回去。如果同时有好多个信息传给b,则b会接受其中发起者编号最小的那个,并将其余的下传回去。如果上传成功,b会接着把信息上传给它的父亲,然后自身进入等待状态。
5.下传:b把信息传给a。解除a的等待状态,接着a继续把信息向着发起者下传过去。如果同时有信息上传和下传到a,视为先下传再上传。
6.当发起者收到下传回来的信息后,传输结束。
7.上传和下传所需时间都是1秒。
8.如果信息的发起者在发出信息时正处于等待状态,该信息直接结束。
现在给你m个时间,第i个事件形如:编号为a的跳蚤在t时刻发起了一次信息传输。现在问你每个信息传输的结束时间是多少。
题解:先将所有时间按$dep_a+t$排序,不难发现排序后只有前面的事件会影响后面的事件,然后我们依次处理每个事件。如果a在上传过程中停在了节点v处,而v正在等待来自b的消息,则一定满足:$dep_a-dep_v+t_a<T_b-(dep_b-dep_v)$,其中T表示结束时间。所以我们可以用树链剖分+线段树维护,然后在链上二分即可。
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=200010;
const int inf=2000000000;
int n,m,cnt;
int to[maxn],nxt[maxn],head[maxn],fa[maxn],p[maxn],q[maxn],dep[maxn],siz[maxn],son[maxn],top[maxn];
int sd[maxn<<2],s[maxn<<2],tag[maxn<<2],ans[maxn];
struct node
{
int x,t,org;
}t[maxn];
void dfs(int x,int tp)
{
top[x]=tp;
p[x]=++q[0],q[q[0]]=x;
if(son[x]) dfs(son[x],tp);
for(int i=head[x];i!=-1;i=nxt[i]) if(to[i]!=son[x]) dfs(to[i],to[i]);
}
inline void add(int a,int b)
{
to[cnt]=b,nxt[cnt]=head[a],head[a]=cnt++;
}
void build(int l,int r,int x)
{
s[x]=tag[x]=-inf;
if(l==r)
{
sd[x]=dep[q[l]]<<1;
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
sd[x]=max(sd[lson],sd[rson]);
}
inline void upd(int x,int y)
{
s[x]=max(s[x],sd[x]+y),tag[x]=max(tag[x],y);
}
inline void pushdown(int x)
{
if(tag[x]!=-inf) upd(lson,tag[x]),upd(rson,tag[x]),tag[x]=-inf;
}
void updata(int l,int r,int x,int a,int b,int c)
{
if(a<=l&&r<=b)
{
upd(x,c);
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a,b,c);
if(b>mid) updata(mid+1,r,rson,a,b,c);
s[x]=max(s[lson],s[rson]);
}
int query(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s[x];
pushdown(x);
int mid=(l+r)>>1;
if(b<=mid) return query(l,mid,lson,a,b);
if(a>mid) return query(mid+1,r,rson,a,b);
return max(query(l,mid,lson,a,b),query(mid+1,r,rson,a,b));
}
bool cmp(const node &a,const node &b)
{
return (dep[a.x]+a.t==dep[b.x]+b.t)?(a.x<b.x):(dep[a.x]+a.t<dep[b.x]+b.t);
}
int solve(int x,int t)
{
if(x==11)
{
x++,x--;
}
int u=x;
while(u)
{
if(query(1,n,1,p[top[u]],p[u])<=dep[x]+t)
{
u=fa[top[u]];
continue;
}
int l=p[top[u]]+1,r=p[u]+1,mid;
while(l<r)
{
mid=(l+r)>>1;
if(query(1,n,1,mid,p[u])>dep[x]+t) l=mid+1;
else r=mid;
}
u=q[l-1];
break;
}
if(!u) u=1;
int ret=2*(dep[x]-dep[u])+t,v=x;
while(top[v]!=top[u])
{
updata(1,n,1,p[top[v]],p[v],ret-dep[x]),v=fa[top[v]];
}
updata(1,n,1,p[u],p[v],ret-dep[x]);
return ret;
}
inline int rd()
{
int ret=0,f=1; char gc=getchar();
while(gc<'0'||gc>'9') {if(gc=='-') f=-f; gc=getchar();}
while(gc>='0'&&gc<='9') ret=ret*10+(gc^'0'),gc=getchar();
return ret*f;
}
int main()
{
int i;
n=rd()+1,m=rd();
dep[1]=1;
memset(head,-1,sizeof(head));
for(i=2;i<=n;i++) fa[i]=rd()+1,add(fa[i],i),dep[i]=dep[fa[i]]+1;
for(i=n;i>=2;i--)
{
siz[i]++,siz[fa[i]]+=siz[i];
if(siz[i]>siz[son[fa[i]]]) son[fa[i]]=i;
}
dfs(1,1);
build(1,n,1);
for(i=1;i<=m;i++) t[i].x=rd()+1,t[i].t=rd(),t[i].org=i;
sort(t+1,t+m+1,cmp);
for(i=1;i<=m;i++)
{
ans[t[i].org]=solve(t[i].x,t[i].t);
}
for(i=1;i<=m;i++) printf("%d ",ans[i]);
return 0;
}//10 9 0 0 0 3 0 4 5 3 8 6 1 6 1 13 5 14 1 16 5 18 7 18 10 21 6 22 4 22
【CF725G】Messages on a Tree 树链剖分+线段树的更多相关文章
- Aizu 2450 Do use segment tree 树链剖分+线段树
Do use segment tree Time Limit: 1 Sec Memory Limit: 256 MB 题目连接 http://www.bnuoj.com/v3/problem_show ...
- 【POJ3237】Tree(树链剖分+线段树)
Description You are given a tree with N nodes. The tree’s nodes are numbered 1 through N and its edg ...
- POJ3237 Tree 树链剖分 线段树
欢迎访问~原文出处——博客园-zhouzhendong 去博客园看该题解 题目传送门 - POJ3237 题意概括 Description 给你由N个结点组成的树.树的节点被编号为1到N,边被编号为1 ...
- Spoj Query on a tree SPOJ - QTREE(树链剖分+线段树)
You are given a tree (an acyclic undirected connected graph) with N nodes, and edges numbered 1, 2, ...
- Water Tree CodeForces 343D 树链剖分+线段树
Water Tree CodeForces 343D 树链剖分+线段树 题意 给定一棵n个n-1条边的树,起初所有节点权值为0. 然后m个操作, 1 x:把x为根的子树的点的权值修改为1: 2 x:把 ...
- 【BZOJ-2325】道馆之战 树链剖分 + 线段树
2325: [ZJOI2011]道馆之战 Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 1153 Solved: 421[Submit][Statu ...
- POJ3237 (树链剖分+线段树)
Problem Tree (POJ3237) 题目大意 给定一颗树,有边权. 要求支持三种操作: 操作一:更改某条边的权值. 操作二:将某条路径上的边权取反. 操作三:询问某条路径上的最大权值. 解题 ...
- B20J_3231_[SDOI2014]旅行_树链剖分+线段树
B20J_3231_[SDOI2014]旅行_树链剖分+线段树 题意: S国有N个城市,编号从1到N.城市间用N-1条双向道路连接,城市信仰不同的宗教,为了方便,我们用不同的正整数代表各种宗教. S国 ...
- BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 )
BZOJ.4034 [HAOI2015]树上操作 ( 点权树链剖分 线段树 ) 题意分析 有一棵点数为 N 的树,以点 1 为根,且树点有边权.然后有 M 个 操作,分为三种: 操作 1 :把某个节点 ...
随机推荐
- Peckham添加引用文件模糊匹配智能提示
下载地址:https://github.com/markohlebar/Peckham 跟VVDocumenter规范注释生成器的安装方式一样: 下载开源工程在Xcode重新编译运行会自动安装此插 ...
- python通过标准输入读取内容,读取键盘输入的内容?接收用户输入?
需求说明: 在交互式脚本中,需要用户手动输入内容,并对内容进行处理.在这里记录下通过 python的内置函数input()读取标注输入的内容.默认的标准输入是键盘. 操作过程: 1.通过input() ...
- [原]unity3D 移动平台崩溃信息收集
http://m.blog.csdn.net/blog/catandrat111/8534287http://m.blog.csdn.net/blog/catandrat111/8534287
- 如何分析解决Android ANR(转载)
转载自:http://blog.csdn.net/dadoneo/article/details/8270107 一:什么是ANR ANR:Application Not Responding,即应用 ...
- it码农之心灵鸡汤(一)
到底该怎么面对工作,到底怎么面临人生.到底怎么面临青春,对于打工的人来说这些一直都是心中一直无法解惑的谜团. 对于人们怎样看待工作,以前华为创始人任正非说过:非常多人问我,来公司工作有没有双休?需不须 ...
- SpringMVC -- 梗概--源码--贰--异常管理
附:实体类 Class : User package com.c61.entity; import java.text.SimpleDateFormat; import java.util.Date; ...
- tomcat运行模式APR安装
centos6.2下,Tomcat运行模式apr安装过程,如下: 一.安装apr [root@vmT227-m5 /]# cd /usr/local/ [root@vmT227-m5 local]# ...
- linux 开机自启
cd /home/dpf 1.vi startup.sh #!/bin/shecho "hello world" >> /home/dpf/test.txt vi mq ...
- linux clamav杀毒软件的安装
一.概述 Linux比其它操作系统更稳定更安全.理论上Linux是有可能被病毒侵害的.但实际上 Linux机器几乎不可能遭受病毒的攻击.所以我这里的问题是为什么要为Linux准备防病毒软件,为了更好理 ...
- N76E003之IIC
I2C 总线提供了一种串行通信方式,用在 MCU 与 EEPROM,LCD模块,温度传感器等等之间控制.I2C 用两条线 (数据线SDA 和时钟线 SCL) 在设备间传输数据.I2C 总线用作主机与从 ...