【NOIP】提高组2016 天天爱跑步
【题意】n个点的树,有m个人同时开始走链,每一步花一秒,n个点都有观察员在ai秒观察,求每个观察员观察到的人数。
【算法】树上差分(主席树||线段树合并)
【题解】一个人的走链可以拆成u-lca和lca-v两部分,可以发现在u-lca链上的点能观察到这个人的w[x],满足所有deep[x]+w[x]相等。同理,在lca-v链上需满足deep[x]-w[x]相等。(画个图,将深度和秒数都标出来就可以得到结论了)
所以可以得到一个点观察到链u-v的条件是【在u-lca上且deep[x]+w[x]=deep[u]】或【在lca-v上且deep[x]-w[x]=deep[v]-time】,其中time=deep[u]+deep[v]-2*deep[lca]。
为了判断是否满足条件,我们可以维护数组A(针对deep[x]+w[x])和数组B(针对deep[x]-w[x])作为判断数组。对于每条链A[deep[u]]+1和B[deep[v]-time]+1,然后点x就可以直接判断满足多少链的要求。
接下来需要解决是否在u-lca或lca-v上的问题,可以运用树上差分。对于一条链,在u点标记A[deep[u]]+1的操作,在v点标记B[deep[v]-time]+1的操作,在lca标记A[deep[u]]-1的操作,在fa[lca]标记B[deep[v]-time]-1的操作(否则lca点同时满足两个要求会计算两次),标记操作需要用类似邻接表的链表接在每个节点处。
然后总的进行一次dfs,每个节点按顺序进行:统计ans[x],将标记操作,dfs子节点,ans[x]=统计ans[x]-ans[x](原)。
★注意:
1.树上差分只能是u+1,v+1,lca-2(或lca-1&&fa(lca)-1),绝对不能是lca处加,因为lca处加会影响到所有子树而不止一条链。
2.树上差分的操作顺序必须是:【统计ans】【操作标记】【DFS子节点】【统计ans-原ans】
对点x,最后统计ans是x的子树和x上面已统计的部分。减原ans相当于减掉x上面已统计的部分。
为什么必须这样做?要是在返回的时候操作标记,就会干扰父节点另一棵子树,所以必须用 [ 当前已统计的所有-x上方已统计的所有 ] 这种后统计-先统计的强操作。
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
using namespace std;
int read(){
char c;int s=,t=;
while(!isdigit(c=getchar()))if(c=='-')t=-;
do{s=s*+c-'';}while(isdigit(c=getchar()));
return s*t;
}
const int maxn=;
int first[maxn],firstA[maxn],firstB[maxn],a[maxn],markA[maxn*],markB[maxn*],tot,totA,totB;
int deep[maxn],f[maxn][],ans[maxn],n,m;
struct edge{int v,w,from;}e[maxn*],A[maxn*],B[maxn*];
void insert(int u,int v){tot++;e[tot].v=v;e[tot].from=first[u];first[u]=tot;}
void insertA(int u,int v,int w){totA++;A[totA].v=v;A[totA].w=w;A[totA].from=firstA[u];firstA[u]=totA;}
void insertB(int u,int v,int w){totB++;B[totB].v=v;B[totB].w=w;B[totB].from=firstB[u];firstB[u]=totB;}
void DFS(int x,int fa){
for(int j=;(<<j)<=deep[x];j++)f[x][j]=f[f[x][j-]][j-];
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa){
deep[e[i].v]=deep[x]+;
f[e[i].v][]=x;
DFS(e[i].v,x);
}
}
int lca(int x,int y){
if(deep[x]<deep[y])swap(x,y);
int d=deep[x]-deep[y];
for(int j=;j<=;j++)if((<<j)&d)x=f[x][j];
if(x==y)return x;
for(int i=;i>=;i--)if((<<i)<=deep[x]&&f[x][i]!=f[y][i]){
x=f[x][i];y=f[y][i];
}
return f[x][];
}
void dfs(int x,int fa){
ans[x]=markA[a[x]+deep[x]]+markB[a[x]-deep[x]+n];//
for(int i=firstA[x];i;i=A[i].from){
if(A[i].w)markA[A[i].v]--;else markA[A[i].v]++;
}
for(int i=firstB[x];i;i=B[i].from){
if(B[i].w)markB[B[i].v]--;else markB[B[i].v]++;
}
for(int i=first[x];i;i=e[i].from)if(e[i].v!=fa)dfs(e[i].v,x);
ans[x]=markA[a[x]+deep[x]]+markB[a[x]-deep[x]+n]-ans[x];
}
int main(){
n=read();m=read();
for(int i=;i<n;i++){
int u=read(),v=read();
insert(u,v);insert(v,u);
}
for(int i=;i<=n;i++)a[i]=read();
DFS(,);f[][]=;
for(int i=;i<=m;i++){
int u=read(),v=read();
int w=lca(u,v);
insertA(u,deep[u],);//0plus 1minus
insertA(f[w][],deep[u],);
insertB(v,deep[u]-*deep[w]+n,);
insertB(w,deep[u]-*deep[w]+n,);
}
for(int i=firstA[];i;i=A[i].from)if(A[i].w)markA[A[i].v]--;else markA[A[i].v]++;
for(int i=firstB[];i;i=B[i].from)if(A[i].w)markB[B[i].v]--;else markB[B[i].v]++;
dfs(,);
for(int i=;i<n;i++)printf("%d ",ans[i]);printf("%d",ans[n]);
return ;
}
顺便一提主席树和线段树合并的做法。
主席树:对每个点询问子树内等于某个值的起点数和等于某个值的终点树,转化为dfs序上的区间权值询问,可以用可持久化权值线段树解决。
线段树合并:线段树下标记录关键值(和差分的两个值一样),然后从叶子往上进行线段树合并和查询,非常套路了。
【NOIP】提高组2016 天天爱跑步的更多相关文章
- NOIP提高组2016 D1T2 【天天爱跑步】
码了一个下午加一个晚上吧...... 题目描述: 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成 ...
- BZOJ4719[NOIP2016提高组Day1T2] 天天爱跑步
#261. [NOIP2016]天天爱跑步 描述 提交 自定义测试 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家 ...
- NOIP2016提高组D1T2 天天爱跑步
n<=300000个点的树,每个点有个人于第Ti秒观测,有m<=300000个人于时间0开始从Sj跑到Tj,速度1个点每秒,输出每个点上的人观察到的跑步的人的数量. 前25分:直接模拟每条 ...
- NOIP2016提高组Day1T2 天天爱跑步 树链剖分 LCA 倍增 差分
原文链接https://www.cnblogs.com/zhouzhendong/p/9275606.html 题目传送门 - 洛谷P1600 题目传送门 - LOJ#2359 题目传送门 - Vij ...
- 题解——洛谷P2827 NOIP提高组 2016 蚯蚓
队列模拟 详细题解待填坑 #include <cstdio> #include <algorithm> #include <queue> #include < ...
- NOIP提高组2016总结
前言 大翻车! 300--: day1 8:30~9:00, 照常看题,思考. 9:00~9:15, 搞定第一题,很水. 9:15~9:45, 思考第二题,我考虑用分深度来处理,想出个个玄学暴力,但刚 ...
- NOIP提高组2016 D2T3 【愤怒的小鸟】
貌似还没有写过状压DP的题目,嗯,刚好今天考了,就拿出来写一写吧. 题目大意: 额,比较懒,这次就不写了... 思路分析: 先教大家一种判断题目是不是状压DP的方法吧. 很简单,那就是--看数据范围! ...
- [NOIP]2016天天爱跑步
[NOIP]2016天天爱跑步 标签: LCA 树上差分 NOIP Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...
- NOIP提高组初赛难题总结
NOIP提高组初赛难题总结 注:笔者开始写本文章时noip初赛新题型还未公布,故会含有一些比较老的内容,敬请谅解. 约定: 若无特殊说明,本文中未知数均为整数 [表达式] 表示:在表达式成立时它的值为 ...
随机推荐
- P4语法(1)基础数据类型和Header
文章学习自:P4语言编程详解 由于原文有一点的年份,所以也继续阅读了相关的最新规范. P4语言规范 基础数据类型 布尔型(bool) 运算符 描述 and 双目运算符,结果为布尔型 or 双目运算符, ...
- lintcode-167-链表求和
167-链表求和 你有两个用链表代表的整数,其中每个节点包含一个数字.数字存储按照在原来整数中相反的顺序,使得第一个数字位于链表的开头.写出一个函数将两个整数相加,用链表形式返回和. 样例 给出两个链 ...
- 访问方式由http改为https curl:(51)
系统访问由http变为https,先申请了CA证书,然后win下浏览器访问时没问题的,但是linux下通过curl的方式访问就报错: curl:(51) SSLcertificate subject ...
- 软工网络15团队作业4——Alpha阶段敏捷冲刺-3
一.当天站立式会议照片: 二.项目进展 昨天已完成的工作: 依靠HTML 逻辑框架等技术完成程序界面前端的实现. 明天计划完成的工作: 依靠css 逻辑框架等技术完成程序界面前端的实现. 工作中遇到的 ...
- 对alpha发布的总结技术随笔
对于今天的alpha发布,首先需要自我检讨,因为我们组没有展示作品.主要的原因还是我们投入的时间不足.我们的项目是约跑App,首先选择做安卓平台的东西,我们大家都需要熟悉新的开发软件Android S ...
- 第三章 持续集成jenkins工具使用之邮件配置
1 Email Extension Plugin插件安装 持续集成很重要的一环就是及时将构建结果通知到对应的责任人,如:构建失败了,至少需要下发通知给造成本次构建失败的开发人员,如果包含自动化测试 ...
- 第二章 IoC
什么是IoC 如何配置IOC Bean的生命周期 多环境配置 条件化配置Bean 什么是IOC? IOC有两层含义, 1.控制反转:将对象实例的创建与销毁的权限交给Spring容器管理,而不再是调用对 ...
- img 和 background-image 优劣比较
一. 简单来说,img是内容部分的东西,css的background-image是修饰性的东西. img------从页面元素来说,如果是页面中的图片是作为内容出现的,比如广告图片,比如产品图片,那么 ...
- [洛谷P3793]由乃救爷爷
题目大意:有$n(n\leqslant2\times10^7)$个数,$m(m\leqslant2\times10^7)$个询问,每次询问问区间$[l,r]$中的最大值.保证数据随机 题解:分块,处理 ...
- POJ3177:Redundant Paths——题解
http://poj.org/problem?id=3177 明显要求桥的一道题. (因为有桥就说明只能从那一条路走,换句话说就是只有一种方法) 求完桥后按照结论(加几条边成双连通图的结论,不会请ba ...