https://www.luogu.org/problem/show?pid=1600

题目描述

小c同学认为跑步非常有趣,于是决定制作一款叫做《天天爱跑步》的游戏。«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务。

这个游戏的地图可以看作一一棵包含 个结点和 条边的树, 每条边连接两个结点,且任意两个结点存在一条路径互相可达。树上结点编号为从的连续正整数。

现在有个玩家,第个玩家的起点为 ,终点为  。每天打卡任务开始时,所有玩家在第秒同时从自己的起点出发, 以每秒跑一条边的速度, 不间断地沿着最短路径向着自己的终点跑去, 跑到终点后该玩家就算完成了打卡任务。 (由于地图是一棵树, 所以每个人的路径是唯一的)

小C想知道游戏的活跃度, 所以在每个结点上都放置了一个观察员。 在结点的观察员会选择在第秒观察玩家, 一个玩家能被这个观察员观察到当且仅当该玩家在第秒也理到达了结点  。 小C想知道每个观察员会观察到多少人?

注意: 我们认为一个玩家到达自己的终点后该玩家就会结束游戏, 他不能等待一 段时间后再被观察员观察到。 即对于把结点作为终点的玩家: 若他在第秒重到达终点,则在结点的观察员不能观察到该玩家;若他正好在第秒到达终点,则在结点的观察员可以观察到这个玩家。

输入输出格式

输入格式:

第一行有两个整数 。其中代表树的结点数量, 同时也是观察员的数量, 代表玩家的数量。

接下来 行每行两个整数和 ,表示结点 到结点 有一条边。

接下来一行 个整数,其中第个整数为 , 表示结点出现观察员的时间。

接下来 行,每行两个整数,和,表示一个玩家的起点和终点。

对于所有的数据,保证 。

输出格式:

输出1行 个整数,第个整数表示结点的观察员可以观察到多少人。

输入输出样例

输入样例#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
输出样例#1:

2 0 0 1 1 1 
输入样例#2:

5 3
1 2
2 3
2 4
1 5
0 1 0 3 0
3 1
1 4
5 5
输出样例#2:

1 2 1 0 1 

正解移步 http://www.cnblogs.com/TheRoadToTheGold/p/6677435.html

测试点1——5:

数组a[i][j]表示点i在j时刻经过的人数,然后一个人一个人的dfs,记录时刻time

如果到了终点,递归回退时a[now][time]++

令watch[i]=j表示i号节点观察员在j时刻出现

输出a[i][watch[i]]

void run(int now,int end,int time,int fa)
{
if(now==end)
{
ok=true;
a[now][time]++;
return;
}
if(ok) return;
for(int i=front[now];i;i=nextt[i])
{
if(to[i]==fa) continue;
run(to[i],end,time+,now);
}
if(ok) a[now][time]++;
}

测试点6——8:

树退化为一条链,而且点的编号就是深度

所以对于链上一个观察员,他只能观察到从两个位置出发的人i+watch[i],i-watch[i]

如果i能观察到起点深度比他小的人,那么这个人的终点要>=i

如果i能观察到起点深度比他大的人,那么这个人的终点要<=i

所以,

用链表存储从每个节点起跑的人,

枚举每个观察员,然后判断两个位置的人是否满足要求

void solve2()
{
for(int i=;i<=n;i++)
{
if(i-watch[i]>=)
{
for(int j=front[i-watch[i]];j;j=nextt[j])
{
if(i<=e[to[j]].t) ans[i]++;
}
}
if(i+watch[i]<=n)
{
for(int j=front[i+watch[i]];j;j=nextt[j])
{
if(i>=e[to[j]].t) ans[i]++;
}
}
}
}

测试点9——12:

所有人的起点都是1,假设1号的深度为0,

那么只有观察员节点的深度等于出现时间,他才能观察到

所以先判断深度是否等于出现时间,不等,直接输出0,下一个

若相等,他一定能观察到经过他的所有人

也就是说,以观察员i为根的子树中有跑步者的终点,观察员i就能观察多少人

所以,终点+1,记录每个节点的深度,我用的bfs,单后dfs统计子树1的个数,

kids[]表示答案

void bfs1()
{
queue<node2>q;
cur.d= ;cur.who=; fa[]=;
q.push(cur);
while(!q.empty())
{
cur=q.front(); q.pop();
for(int i=front[cur.who];i;i=nextt[i])
{
if(to[i]==fa[cur.who]) continue;
fa[to[i]]=cur.who;
nxt.d=cur.d+; nxt.who=to[i]; deep[nxt.who]=deep[cur.who]+;
q.push(nxt);
}
}
}
void dfs1(int now)
{
kids[now]=sum[now];
for(int i=front[now];i;i=nextt[i])
{
if(to[i]==fa[now]) continue;
dfs1(to[i]);
kids[now]+=kids[to[i]];
}
}

测试点13——16:

所有人的终点都是1

也就是说,第i个观察员只能观察到第deep[i]+watch[i]层的跑步者

所以,若跑步者能被观察员i观察到,要满足以下两个条件:

1、在起点观察员i的子树内

2、起点的层数=deep[i]+watch[i]

先对原树dfs一遍,记录观察员i的子树dfs序范围in[i]——out[i]

对每一层维护一颗线段树,动态开节点

查询时,找到deep[i]+watch[i]这一层的线段树,查in[i]——out[i]有多少个起点

void add(int &now,int pos,int l,int r,int cnt)
{
if(!now) now=++tot2;
sum[now]+=cnt;
if(l==r) return;
int mid=l+r>>;
if(pos<=mid) add(lc[now],pos,l,mid,cnt);
else add(rc[now],pos,mid+,r,cnt);
}
void dfs(int now,int pre)
{
in[now]=++tot;
add(root[deep[now]],tot,,n,siz[now]);
for(int i=front[now];i;i=nxt[i])
{
if(to[i]==pre) continue;
deep[to[i]]=deep[now]+;
maxn=max(maxn,deep[to[i]]);
dfs(to[i],now);
}
out[now]=tot;
}
void query(int now,int opl,int opr,int l,int r)
{
if(!now) return;
if(l>=opl&&r<=opr) { ans+=sum[now]; return; }
int mid=l+r>>;
if(opl<=mid) query(lc[now],opl,opr,l,mid);
if(opr>mid) query(rc[now],opl,opr,mid+,r);
}

测试点17——20:

正解移步 http://www.cnblogs.com/TheRoadToTheGold/p/6677435.html

所有暴力综合代码

#include<queue>
#include<cstdio>
#include<algorithm>
#define N1 1000
#define N2 100000
#define N3 300000
using namespace std;
int n,m,uu,vv;
int watch[N2];
int front[N2],nextt[N2*],to[N2*],tot;
void add(int u,int v)
{
to[++tot]=v; nextt[tot]=front[u]; front[u]=tot;
}
namespace one_to_five
{
int a[N1][N1];
bool ok;
void run(int now,int end,int time,int fa)
{
if(now==end)
{
ok=true;
a[now][time]++;
return;
}
if(ok) return;
for(int i=front[now];i;i=nextt[i])
{
if(to[i]==fa) continue;
run(to[i],end,time+,now);
}
if(ok) a[now][time]++;
}
void solve()
{
for(int i=;i<n;i++)
{
scanf("%d%d",&uu,&vv);
add(uu,vv);
add(vv,uu);
}
for(int i=;i<=n;i++) scanf("%d",&watch[i]);
for(int i=;i<=m;i++)
{
scanf("%d%d",&uu,&vv);
ok=false;
run(uu,vv,,);
}
for(int i=;i<=n;i++) printf("%d ",a[i][watch[i]]);
}
}
namespace six_to_eight
{
struct node { int s,t; } e[N2];
int ans[N2];
void solve2()
{
for(int i=;i<=n;i++)
{
if(i-watch[i]>=)
{
for(int j=front[i-watch[i]];j;j=nextt[j])
{
if(i<=e[to[j]].t) ans[i]++;
}
}
if(i+watch[i]<=n)
{
for(int j=front[i+watch[i]];j;j=nextt[j])
{
if(i>=e[to[j]].t) ans[i]++;
}
}
}
}
void solve()
{
for(int i=;i<n;i++) scanf("%d%d",&uu,&vv);
for(int i=;i<=n;i++) scanf("%d",&watch[i]);
for(int i=;i<=m;i++)
{
scanf("%d%d",&e[i].s,&e[i].t);
add(e[i].s,i);
}
solve2();
for(int i=;i<=n;i++) printf("%d ",ans[i]);
}
}
namespace nine_to_twelve
{
struct node2 { int d,who; }cur,nxt;
int sum[N2],deep[N2],fa[N2],kids[N2];
void bfs1()
{
queue<node2>q;
cur.d= ;cur.who=; fa[]=;
q.push(cur);
while(!q.empty())
{
cur=q.front(); q.pop();
for(int i=front[cur.who];i;i=nextt[i])
{
if(to[i]==fa[cur.who]) continue;
fa[to[i]]=cur.who;
nxt.d=cur.d+; nxt.who=to[i]; deep[nxt.who]=deep[cur.who]+;
q.push(nxt);
}
}
}
void dfs1(int now)
{
kids[now]=sum[now];
for(int i=front[now];i;i=nextt[i])
{
if(to[i]==fa[now]) continue;
dfs1(to[i]);
kids[now]+=kids[to[i]];
}
}
void solve()
{
int u,v;
for(int i=;i<n;i++)
{
scanf("%d%d",&uu,&vv);
add(uu,vv);
add(vv,uu);
}
bfs1();
for(int i=;i<=n;i++) scanf("%d",&watch[i]);
for(int i=;i<=m;i++)
{
scanf("%d%d",&uu,&vv);
sum[vv]++;
}
dfs1();
for(int i=;i<=n;i++)
if(watch[i]==deep[i]) printf("%d ",kids[i]);
else printf("0 ");
}
}
namespace thirteen_to_sixteen
{
int ans,tot2,maxn;
int watch[N2],siz[N2];
int in[N2],out[N2],deep[N2];
int root[N2],lc[N2*],rc[N2*],sum[N2*];
void insert(int &now,int pos,int l,int r,int cnt)
{
if(!now) now=++tot2;
sum[now]+=cnt;
if(l==r) return;
int mid=l+r>>;
if(pos<=mid) insert(lc[now],pos,l,mid,cnt);
else insert(rc[now],pos,mid+,r,cnt);
}
void dfs(int now,int pre)
{
in[now]=++tot;
insert(root[deep[now]],tot,,n,siz[now]);
for(int i=front[now];i;i=nextt[i])
{
if(to[i]==pre) continue;
deep[to[i]]=deep[now]+;
maxn=max(maxn,deep[to[i]]);
dfs(to[i],now);
}
out[now]=tot;
}
void query(int now,int opl,int opr,int l,int r)
{
if(!now) return;
if(l>=opl&&r<=opr) { ans+=sum[now]; return; }
int mid=l+r>>;
if(opl<=mid) query(lc[now],opl,opr,l,mid);
if(opr>mid) query(rc[now],opl,opr,mid+,r);
}
void solve()
{
for(int i=;i<n;i++)
{
scanf("%d%d",&uu,&vv);
add(uu,vv);
}
for(int i=;i<=n;i++) scanf("%d",&watch[i]);
tot=;
while(m--)
{
scanf("%d%d",&uu,&vv);
siz[uu]++;
}
dfs(,);
for(int i=;i<=n;i++)
{
ans=;
if(deep[i]+watch[i]<=maxn) query(root[deep[i]+watch[i]],in[i],out[i],,n);
printf("%d ",ans);
}
} }
int main()
{
scanf("%d%d",&n,&m);
if(n%<=) one_to_five::solve();
else if(n%==) six_to_eight::solve();
else if(n%==) nine_to_twelve::solve();
else if(n%==) thirteen_to_sixteen::solve();
}

NOIP2016 天天爱跑步 80分暴力的更多相关文章

  1. NOIP 2016 天天爱跑步 80分暴力

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...

  2. [NOIp2016]天天爱跑步 线段树合并

    [NOIp2016]天天爱跑步 LG传送门 作为一道被毒瘤出题人们玩坏了的NOIp经典题,我们先不看毒瘤的"动态爱跑步"和"天天爱仙人掌",回归一下本来的味道. ...

  3. [Noip2016]天天爱跑步 LCA+DFS

    [Noip2016]天天爱跑步 Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要玩家每天按时上线,完成打卡任 ...

  4. 【LG1600】[NOIP2016]天天爱跑步

    [LG1600][NOIP2016]天天爱跑步 题面 洛谷 题解 考虑一条路径\(S\rightarrow T\)是如何给一个观测点\(x\)造成贡献的, 一种是从\(x\)的子树内出来,另外一种是从 ...

  5. BZOJ4719 [Noip2016]天天爱跑步

    本文版权归ljh2000和博客园共有,欢迎转载,但须保留此声明,并给出原文链接,谢谢合作. 本文作者:ljh2000作者博客:http://www.cnblogs.com/ljh2000-jump/转 ...

  6. noip2016天天爱跑步

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 个结点 ...

  7. NOIP2016天天爱跑步 题解报告【lca+树上统计(桶)】

    题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养成类游戏,需要玩家每天按时上线,完成打卡任务. 这个游戏的地图可以看作一一棵包含 nn个 ...

  8. bzoj 4719: [Noip2016]天天爱跑步

    Description 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.?天天爱跑步?是一个养成类游戏,需要 玩家每天按时上线,完成打卡任务.这个游戏的地图可以看作一一 ...

  9. 4719: [Noip2016]天天爱跑步

    Time Limit: 40 Sec Memory Limit: 512 MB Submit: 1986 Solved: 752 [Submit][Status][Discuss] Descripti ...

随机推荐

  1. 【BZOJ3282】Tree (Link-Cut Tree)

    [BZOJ3282]Tree (Link-Cut Tree) 题面 BZOJ权限题呀,良心luogu上有 题解 Link-Cut Tree班子提 最近因为NOIP考炸了 学科也炸了 时间显然没有 以后 ...

  2. 【BZOJ4010】【HNOI2015】菜肴制作(拓扑排序)

    [BZOJ4010][HNOI2015]菜肴制作(拓扑排序) 题面 Description 知名美食家小 A被邀请至ATM 大酒店,为其品评菜肴. ATM 酒店为小 A 准备了 N 道菜肴,酒店按照为 ...

  3. 一个10年Java程序员的年终总结,献给还在迷茫中的你

    我越来越担心我作为一个Java程序员的未来. 恍然间,发现自己在这个行业里已经摸爬滚打将近10年了,原以为自己就凭已有的项目经验和工作经历怎么着也应该算得上是一个业内比较资历的人士了,但是今年在换工作 ...

  4. PyCharm的注册码获取

    1.在server选项里边输入 http://elporfirio.com:1017/就可以了.  2.server选项里边输入 http://idea.imsxm.com/ 3.server选项里边 ...

  5. 剑指offer-(19)顺时针打印矩阵

    题目描述 输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2, ...

  6. wpf研究之道-grid控件

    想要说些什么,却不知道从哪开始."形而上谓之道,形而下谓之器".与其坐而论道,不如脚踏实地,从最实用的地方开始. 我们先来看看wpf中的grid控件.grid控件是个网格的布局控件 ...

  7. error:安装手电筒程序后在打开程序后报错:你的camera flashlight正在被其他程序占据

    Q:没打开权限 A:设置里面,把这个app的camera权限打开就行了

  8. python selenium 自动化测试web

    如何使用python完成自动化测试web页面呢?首选selenium   那基于python的selenium如何使用,下面看一段测试案例: 基于python的selenium 安装方法: pip i ...

  9. 防F12审查元素扒代码:按下F12关闭当前页面

    有的时候我看别人的网站的某个部分做的比较好我都会通过按F12审查元素来查看别人的代码,那么如果不然别人查看自己网站的代码呢.一段JavaScript代码即可实现上述功能,插入到footer.php或者 ...

  10. cxGrid_Q31584 cxgrid 拖放移动记录

    cxgrid 拖放移动记录,cxgrid 拖放,cxgrid 拖动记录,cxgrid 鼠标拖动记录 这是cxgrid开发公司回复客户时所发送的源码项目,用于实现鼠标拖动记录,改变记录在表格中的位置,所 ...