NOIP 2016 天天爱跑步 80分暴力
题目描述
小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。
这个游戏的地图可以看作一一棵包含 个结点和
条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从
到
的连续正整数。
现在有个玩家,第
个玩家的起点为
,终点为
。每天打卡任务开始时,所有玩家在第
秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)
小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选择在第
秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第
秒也理到达了结点
。 小C想知道每个观察员会观察到多少人?
注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点作为终点的玩家: 若他在第
秒重到达终点,则在结点
的观察员不能观察到该玩家;若他正好在第
秒到达终点,则在结点
的观察员可以观察到这个玩家。
输入输出格式
输入格式:
第一行有两个整数和
。其中
代表树的结点数量, 同时也是观察员的数量,
代表玩家的数量。
接下来 行每行两个整数
和
,表示结点
到结点
有一条边。
接下来一行 个整数,其中第
个整数为
, 表示结点
出现观察员的时间。
接下来 行,每行两个整数
,和
,表示一个玩家的起点和终点。
对于所有的数据,保证 。
输出格式:
输出1行 个整数,第
个整数表示结点
的观察员可以观察到多少人。
输入输出样例
6 3
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6
2 0 0 1 1 1
5 3
1 2
2 3
2 4
1 5
0 1 0 3 0
3 1
1 4
5 5
1 2 1 0 1
说明
【样例1说明】
对于1号点,,故只有起点为1号点的玩家才会被观察到,所以玩家1和玩家2被观察到,共有2人被观察到。
对于2号点,没有玩家在第2秒时在此结点,共0人被观察到。
对于3号点,没有玩家在第5秒时在此结点,共0人被观察到。
对于4号点,玩家1被观察到,共1人被观察到。
对于5号点,玩家1被观察到,共1人被观察到。
对于6号点,玩家3被观察到,共1人被观察到。
【子任务】
每个测试点的数据规模及特点如下表所示。 提示: 数据范围的个位上的数字可以帮助判断是哪一种数据类型。

【提示】
如果你的程序需要用到较大的栈空问 (这通常意味着需要较深层数的递归), 请务必仔细阅读选手日录下的文本当rumung:/stact.p″, 以了解在最终评测时栈空问的限制与在当前工作环境下调整栈空问限制的方法。
在最终评测时,调用栈占用的空间大小不会有单独的限制,但在我们的工作
环境中默认会有 8 MB 的限制。 这可能会引起函数调用层数较多时, 程序发生
栈溢出崩溃。
我们可以使用一些方法修改调用栈的大小限制。 例如, 在终端中输入下列命
令 ulimit -s 1048576
此命令的意义是,将调用栈的大小限制修改为 1 GB。
例如,在选手目录建立如下 sample.cpp 或 sample.pas

将上述源代码编译为可执行文件 sample 后,可以在终端中运行如下命令运
行该程序
./sample
如果在没有使用命令“ ulimit -s 1048576”的情况下运行该程序, sample
会因为栈溢出而崩溃; 如果使用了上述命令后运行该程序,该程序则不会崩溃。
特别地, 当你打开多个终端时, 它们并不会共享该命令, 你需要分别对它们
运行该命令。
请注意, 调用栈占用的空间会计入总空间占用中, 和程序其他部分占用的内
存共同受到内存限制。
思路:
这题真特么恶心;
明明noi难度的题非要搞到noip里;
这题一看范围就懵了;
然后,我们就开始写暴力;
看第一个数据,n<=1000;
恩,纯暴力就好,找两点的lca,往上跳的同时观察;
看第二个数据,树退化成了链;
按说树退化成了链,应该是更好做一些,然而,蒟蒻不会;
最后蒟蒻的做法是
枚举每个点;
每个点的可以被观察到时,这条路径的起点是却定的;
所以,我们只需判断这个起点的路径是否包括这个点;
可能被极限数据卡成n*n,但是出题人还是很良心的;
看第三个数据,路径起点都是1;
当起点都是1的时候;
对整棵树以1为根开始树剖;
然后,我们就发现,每个点的深度就是这个点上的人跑的时间;
然后判断wi是否等于deepi就好;
看第4个数据,路径终点都是1;
这个就有点恶心了;
但是我还是拿到了手;
我们先进行dfs,把树上每个节点的子树都用区间表示;
然后针对每个深度建立一颗线段树;
然后,用当树为链时判断起点的方法判断起点在哪个深度;
然后用线段树logn求出;
恩,水到80分了;
剩下20分死活水不出来;
来,上代码:
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm> #define maxn 100005
#define maxn1 1005
//暴力dfs
#define maxn2 99994
//树变成一条链
#define maxn3 99995
//所有si=1
#define maxn4 99996
//所有ti=1 using namespace std; struct STreeNodeType {
int l,r,dis,lc,rc;
};
struct STreeNodeType stree[maxn*]; struct TreeNodeType {
int l,r,dis,mid,flag;
};
struct TreeNodeType tree[maxn<<]; struct ListType {
int e,v;
};
struct ListType eli[maxn]; int root[maxn],li[maxn],ri[maxn];
int n,m,head[maxn],E[maxn<<],V[maxn<<],cnt,apti[maxn];
int f[maxn],deep[maxn],dfn[maxn],fdfn,times[maxn],tot;
int lis[maxn],size[maxn],top[maxn],bel[maxn],id[maxn]; char Cget; inline void in(int &now)
{
now=,Cget=getchar();
while(Cget>''||Cget<'') Cget=getchar();
while(Cget>=''&&Cget<='')
{
now=now*+Cget-'';
Cget=getchar();
}
} void dfs_dfn(int now,int fa)
{
f[now]=fa,deep[now]=deep[fa]+,dfn[now]=++fdfn;
for(int i=head[now];i;i=E[i])
{
if(V[i]==fa) continue;
dfs_dfn(V[i],now);
}
} inline void slca(int x,int y)
{
int x_=x,y_=y,lca,ti=;
while(dfn[x_]!=dfn[y_])
{
if(dfn[x_]<dfn[y_]) swap(x_,y_);
while(dfn[x_]>dfn[y_]) x_=f[x_];
}
lca=x_;
while(x!=lca)
{
if(ti==apti[x]) times[x]++;
x=f[x],ti++;
}
if(ti==apti[lca]) times[lca]++;
ti+=deep[y]-deep[lca];
while(y!=lca)
{
if(ti==apti[y]) times[y]++;
y=f[y],ti--;
}
} void dfs_tree(int now,int fa)
{
int pos=cnt++;
f[now]=fa;
deep[now]=deep[fa]+;
for(int i=head[now];i;i=E[i])
{
if(V[i]==fa) continue;
dfs_tree(V[i],now);
}
size[now]=cnt-pos;
} void dfs_tree_(int now,int chain)
{
int pos=;
top[now]=chain,bel[++cnt]=now,id[now]=cnt;
for(int i=head[now];i;i=E[i])
{
if(V[i]==f[now]) continue;
if(size[V[i]]>size[pos]) pos=V[i];
}
if(pos==) return ;
dfs_tree_(pos,chain);
for(int i=head[now];i;i=E[i])
{
if(V[i]==pos||V[i]==f[now]) continue;
dfs_tree_(V[i],V[i]);
}
} inline void tree_down(int now)
{
if(tree[now].l==tree[now].r) return ;
tree[now<<].flag+=tree[now].flag;
tree[now<<|].flag+=tree[now].flag;
tree[now<<].dis+=tree[now].flag*(tree[now<<].r-tree[now<<].l+);
tree[now<<|].dis+=tree[now].flag*(tree[now<<|].r-tree[now<<|].l+);
tree[now].flag=;
} void tree_build(int now,int l,int r)
{
tree[now].l=l,tree[now].r=r;
if(l==r) return ;
tree[now].mid=l+r>>;
tree_build(now<<,l,tree[now].mid);
tree_build(now<<|,tree[now].mid+,r);
} void tree_change(int now,int l,int r)
{
if(tree[now].l==l&&tree[now].r==r)
{
tree[now].flag++;
tree[now].dis+=r-l+;
return ;
}
if(tree[now].flag) tree_down(now);
if(l>tree[now].mid) tree_change(now<<|,l,r);
else if(r<=tree[now].mid) tree_change(now<<,l,r);
else
{
tree_change(now<<,l,tree[now].mid);
tree_change(now<<|,tree[now].mid+,r);
}
tree[now].dis=tree[now<<].dis+tree[now<<|].dis;
} void solve_add(int x,int y)
{
while(top[x]!=top[y])
{
if(deep[x]<deep[y]) swap(x,y);
tree_change(,id[top[x]],id[x]);
x=f[top[x]];
}
if(deep[x]>deep[y]) swap(x,y);
tree_change(,id[x],id[y]);
} void tree_count_si(int now)
{
if(tree[now].l==tree[now].r)
{
if(deep[bel[tree[now].l]]==apti[bel[tree[now].l]])
{
times[bel[tree[now].l]]+=tree[now].dis;
}
return ;
}
if(tree[now].flag) tree_down(now);
tree_count_si(now<<);
tree_count_si(now<<|);
} void st_add(int &now,int l,int r,int to,int x)
{
if(now==)
{
now=++tot;
stree[now].l=l,stree[now].r=r;
}
stree[now].dis+=x;
if(l==r) return ;
int mid=l+r>>;
if(to>mid) st_add(stree[now].rc,mid+,r,to,x);
else st_add(stree[now].lc,l,mid,to,x);
} void dfs_ti(int now,int fa)
{
li[now]=++cnt,deep[now]=deep[fa]+;
st_add(root[deep[now]],,n,li[now],size[now]);
for(int i=head[now];i;i=E[i])
{
if(V[i]==fa) continue;
dfs_ti(V[i],now);
}
ri[now]=cnt;
} int query(int now,int l,int r)
{
if(now==) return ;
if(stree[now].l==l&&stree[now].r==r) return stree[now].dis;
int mid=stree[now].l+stree[now].r>>;
if(l>mid) return query(stree[now].rc,l,r);
else if(r<=mid) return query(stree[now].lc,l,r);
else return query(stree[now].lc,l,mid)+query(stree[now].rc,mid+,r);
} int main()
{
in(n),in(m);int u,v;
for(int i=;i<n;i++)
{
in(u),in(v);
V[++cnt]=v,E[cnt]=head[u],head[u]=cnt;
V[++cnt]=u,E[cnt]=head[v],head[v]=cnt;
}
for(int i=;i<=n;i++) in(apti[i]);
if(n<=maxn1)
{
dfs_dfn(,);
while(m--)
{
in(u),in(v);
slca(u,v);
}
for(int i=;i<=n;i++) printf("%d ",times[i]);
}else if(n==maxn2)
{
cnt=;
while(m--)
{
in(u),in(v);
eli[++cnt].v=v,eli[cnt].e=lis[u],lis[u]=cnt;
}
for(int i=;i<=n;i++)
{
u=i-apti[i],v=i+apti[i];
if(u>)
{
for(int j=lis[u];j;j=eli[j].e)
{
if(eli[j].v>=i) times[i]++;
}
}
if(v<=n)
{
for(int j=lis[v];j;j=eli[j].e)
{
if(eli[j].v<=i) times[i]++;
}
}
printf("%d ",times[i]);
}
}else if(n==maxn3)
{
deep[]=-;
cnt=,dfs_tree(,);
cnt=,dfs_tree_(,);
tree_build(,,n);
while(m--)
{
in(u),in(v);
solve_add(u,v);
}
tree_count_si();
for(int i=;i<=n;i++) printf("%d ",times[i]);
}else if(n==maxn4)
{
while(m--)
{
in(u),in(v);
size[u]++;
}
deep[]=;
cnt=,tot=,dfs_ti(,);
for(int i=;i<=n;i++)
{
int pos=deep[i]+apti[i];
printf("%d ",query(root[pos],li[i],ri[i]));
}
}
return ;
}
NOIP 2016 天天爱跑步 80分暴力的更多相关文章
- NOIP2016 天天爱跑步 80分暴力
https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...
- [NOIP]2016天天爱跑步
[NOIP]2016天天爱跑步 标签: LCA 树上差分 NOIP Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...
- Noip 2016 天天爱跑步 题解
[NOIP2016]天天爱跑步 时间限制:2 s 内存限制:512 MB [题目描述] 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...
- [NOIp 2016]天天爱跑步
Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图 ...
- NOIP 2016 天天爱跑步 (luogu 1600 & uoj 261) - 线段树
题目传送门 传送点I 传送点II 题目大意 (此题目不需要大意,我认为它已经很简洁了) 显然线段树合并(我也不知道哪来这么多显然) 考虑将每条路径拆成两条路径 s -> lca 和 t -> ...
- 【NOIP】提高组2016 天天爱跑步
[题意]n个点的树,有m个人同时开始走链,每一步花一秒,n个点都有观察员在ai秒观察,求每个观察员观察到的人数. [算法]树上差分(主席树||线段树合并) [题解]一个人的走链可以拆成u-lca和lc ...
- 【noip 2016】 蚯蚓(50分)(earthworm)
50分小程序,写了2天- 题目在这里 一个单调队列,写的都是p=0的点,考试的时候要是弄到这些分的话--不说了-- 羡慕AC的神犇啊,54行的满分程序,而我-- #include <iostre ...
- [luogu]P1600 天天爱跑步[LCA]
[luogu]P1600 [NOIP 2016]天天爱跑步 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上 ...
- [NOIP2016-day1-T2]天天爱跑步running_题解
题目来源:http://www.lydsy.com/JudgeOnline/problem.php?id=4719 镇楼图: noip滚粗后..订正的第一题. 题目大意: 有若干条路径在一棵树上,问每 ...
随机推荐
- Codeforces Round #461 (Div. 2) C. Cave Painting
C. Cave Painting time limit per test 1 second memory limit per test 256 megabytes Problem Descriptio ...
- TCP/IP网络编程之多线程服务端的实现(二)
线程存在的问题和临界区 上一章TCP/IP网络编程之多线程服务端的实现(一)的thread4.c中,我们发现多线程对同一变量进行加减,最后的结果居然不是我们预料之内的.其实,如果多执行几次程序,会发现 ...
- TCP/IP网络编程之优于select的epoll(二)
基于epoll的回声服务端 在TCP/IP网络编程之优于select的epoll(一)这一章中,我们介绍了epoll的相关函数,接下来给出基于epoll的回声服务端示例. echo_epollserv ...
- TCP/IP网络编程之多进程服务端(二)
信号处理 本章接上一章TCP/IP网络编程之多进程服务端(一),在上一章中,我们介绍了进程的创建和销毁,以及如何销毁僵尸进程.前面我们讲过,waitpid是非阻塞等待子进程销毁的函数,但有一个不好的缺 ...
- Dataflow编程模型和spark streaming结合
Dataflow编程模型和spark streaming结合 主要介绍一下Dataflow编程模型的基本思想,后面再简单比较一下Spark streaming的编程模型 == 是什么 == 为用户提 ...
- 42、通过ontouch检测expandableListview的单击、长按、列表滚动
一.在model定义变量: public boolean isExpandableListviewScroll = false;//这个是 首先监听expandableListview的滚动: Exp ...
- Oracle 学习笔记(Windows 环境下安装 + PL/SQL)
Oracle 安装.PL/SQL 配置使用 前言:因更换机械硬盘为 SSD 固态硬盘装了新 Windows 7 系统,需要重新搭建开发环境,把 Oracle 安装过程和 PL/SQL 配置使用做下笔 ...
- Python-S9——Day100-Web前端框架之Vue
01 课程简介: 02 let和const: 03 箭头函数: 04 对象的单体模式: 05 nodejs介绍和npm操作: 06 webpack.babel介绍和vue的第一个案例: 07 昨日内容 ...
- C# 方法重载 overload、方法重写 override、隐藏 new
一.重载:同一个作用域内发生(比如一个类里面),定义一系列同名方法,但是方法的参数列表不同.这样才能通过传递不同的参数来决定到底调用哪一个. 值得注意的是,方法重载只有通过参数不同来判断调用哪个方法, ...
- Leetcode 542.01矩阵
01矩阵 给定一个由 0 和 1 组成的矩阵,找出每个元素到最近的 0 的距离. 两个相邻元素间的距离为 1 . 示例 1: 输入: 0 0 0 0 1 0 0 0 0 输出: 0 0 0 0 1 0 ...