题目链接

problem

solution

这是一道一个顶六个的好题!!!

说一下各档部分分怎么写吧。

先看一下\(S_i=1\)和\(T_i=1\)的部分分怎么写。

如果\(S_i=1\)

当且仅当第\(i\)个点的深度\(dep_i=w_i\)时,该点可以观察到人。且观察到的人数为终点位于其子树内的人数。

如果\(T_i=1\)

这时第\(i\)个点能观察到的人数就是子树内起点深度=\(dep_i+w[i]\)的人数。用个桶记录下来这个值。

如果得到该子树内\(dep[s_i]=dep_i+w[i]\)的数量呢?

其实很简单。当第一次\(bfs\)到点\(i\)时,记录下桶中\(dep_i+w[i]\)的值,\(dfs\)整颗子树之后再得到一个值。将两个值作差即可。

下面说满分做法

将路径分为从\(s\)到\(lca\)和从\(lca\)到\(t\)两部分讨论。

先看从\(s\)到\(lca\)这部分。

那么对于一个点\(i\)就是要找\(dep[lca]<=dep[i]\)且\(dep_s=dep_i+w_i\)的数量。

不考虑红色部分限制的话,就和\(S_i=1\)的部分分同样做法。

然后看\(lca\)到\(t\)这部分

对于一个点\(i\)就是要找\(dep[lca]<=dep[i]\)且\(len - (dep[t]-dep[i])=w[i]\)即\(w[i] - dep[i] = len - dep[t]\)的数量(\(len\)表示该路径长度)。

这个不考虑红色部分限制的话,也可以用一个桶维护出来。

然后考虑解决红色部分限制

其实只要在dfs完一个点的子树后,将以该点为\(lca\)的路径贡献全部从桶中删除即可。

code

#include<cstdio>
#include<iostream>
#include<ctime>
#include<algorithm>
#include<cstdlib>
#include<queue>
#include<vector>
using namespace std;
typedef long long ll; ll read() {
ll x = 0,f = 1;char c = getchar();
while(c < '0' || c > '9') {
if(c == '-') f = -1;
c = getchar();
}
while(c >= '0' && c <= '9') {
x = x * 10 + c - '0';
c = getchar();
}
return x * f;
}
int n,m;
namespace BF1 {
const int N = 1010;
int a[N],b[N];
void main() { for(int i = 1;i < n;++i) {read();read();} for(int i = 1;i <= n;++i) {
int k = read();
if(!k) b[i] = 1;
} int ans = 0;
for(int i = 1;i <= m;++i) {
int x = read(),y = read();
a[x]++;
}
for(int i = 1;i <= n;++i)
printf("%d ",a[i] * b[i]); }
}
namespace BF2 {
int a[1010];
void main() {
for(int i = 1;i < n;++i) {read();read();}
for(int i = 1;i <= n;++i) read();
for(int i = 1;i <= m;++i) {
int x = read(),y = read();
a[x]++;
}
for(int i = 1;i <= n;++i)
printf("%d ",a[i]);
}
}
namespace BF3 {
const int N = 1010;
struct node {
int v,nxt;
}e[N << 1];
int w[N],ans[N];
int head[N],ejs;
void add(int u,int v) {
e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;
}
int dfs(int u,int fa,int V,int now) {
if(u == V) {
ans[u] += w[u] == now;
return 1;
}
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(v == fa) continue;
if(dfs(v,u,V,now + 1)) {
ans[u] += (w[u] == now);
return 1;
}
}
return 0;
}
void main() {
for(int i = 1;i < n;++i) {
int u = read(),v = read();
add(v,u);add(u,v);
} for(int i = 1;i <= n;++i) w[i] = read(); for(int i = 1;i <= m;++i) {
int u = read(),v = read();
dfs(u,0,v,0);
}
for(int i = 1;i <= n;++i) printf("%d ",ans[i]);
}
}
namespace BF4 {
const int N = 100010;
vector<int>v[N];
int w[N],ans[N];
int erfen(int pos,int x) {
int l = 0,r = v[pos].size() - 1,ret = r + 1; while(l <= r) {
int mid = (l + r) >> 1;
if(v[pos][mid] >= x) ret = mid,r = mid - 1;
else l = mid + 1;
} return ret + 1;
}
void main() {
for(int i = 1;i < n;++i) read(),read();
for(int i = 1;i <= n;++i) w[i] = read();
for(int i = 1;i <= m;++i) {
int u = read(),V = read();
v[u].push_back(V);
}
for(int i = 1;i <= n;++i) sort(v[i].begin(),v[i].end()); for(int i = 1;i <= n;++i) {
int k = i - w[i];
if(w[i] == 0) {
ans[i] += v[k].size();continue;
}
if(k > 0) {
// int p = erfen(k,i);
// ans[i] += v[k].size() - p + 1;
for(vector<int>::iterator it = v[k].begin();it != v[k].end();++it) {
if(*it >= i) ans[i]++;
}
}
k = i + w[i];
if(k <= n) {
// int p = erfen(k,i);
// ans[i] += p - 1;
for(vector<int>::iterator it = v[k].begin();it != v[k].end();++it)
if(*it <= i) ans[i]++;
}
}
for(int i = 1;i <= n;++i) printf("%d ",ans[i]);
}
}
namespace BF5 {
const int N = 100010;
struct node {
int v,nxt;
}e[N << 1];
int head[N],ejs;
void add(int u,int v) {
e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;
}
int siz[N],dep[N];
void dfs(int u,int fa) {
dep[u] = dep[fa] + 1;
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(v == fa) continue;
dfs(v,u);
siz[u] += siz[v];
}
}
int w[N];
void main() {
for(int i = 1;i < n;++i) {
int u = read(),v = read();
add(u,v);add(v,u);
}
for(int i = 1;i <= n;++i) w[i] = read();
for(int i = 1;i <= m;++i) {
int x = read(),y = read();
siz[y]++;
}
dep[0] = -1;
dfs(1,0);
for(int i = 1;i <= n;++i) {
if(dep[i] == w[i]) printf("%d ",siz[i]);
else printf("0 ");
}
}
}
namespace BF6 {
const int N = 100010;
struct node {
int v,nxt;
}e[N << 1];
int head[N],ejs;
void add(int u,int v) {
e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;
}
int w[N],dep[N],ans[N];
int tong[N << 1],siz[N << 1];
void solve(int u,int fa) {
dep[u] = dep[fa] + 1;
int k = tong[dep[u] + w[u]];
tong[dep[u]] += siz[u];
for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(v == fa) continue;
solve(v,u);
}
ans[u] = tong[dep[u] + w[u]] - k;
}
void main() {
for(int i = 1;i < n;++i) {
int u = read(),v = read();
add(v,u);add(u,v);
} for(int i = 1;i <= n;++i) w[i] = read();
for(int i = 1;i <= m;++i) {
int x = read(),y = read();
siz[x]++;
} solve(1,0);
for(int i = 1;i <= n;++i) printf("%d ",ans[i]);
}
}
namespace BF7 {
const int N = 300000,logN = 20;
struct node {
int v,nxt;
}e[N << 1];
int head[N],ejs;
void add(int u,int v) {
e[++ejs].v = v;e[ejs].nxt = head[u];head[u] = ejs;
}
int dep[N],w[N],lca[N][20];
void get_lca(int u,int fa) {
dep[u] = dep[fa] + 1;
for(int i = 1;i < logN;++i) lca[u][i] = lca[lca[u][i - 1]][i - 1]; for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(v == fa) continue;
lca[v][0] = u;
get_lca(v,u);
}
}
int LCA(int x,int y) {
if(dep[x] < dep[y]) swap(x,y); for(int i = logN - 1;i >= 0;--i)
if(dep[lca[x][i]] >= dep[y]) x = lca[x][i]; for(int i = logN - 1;i >= 0;--i)
if(lca[x][i] != lca[y][i]) x = lca[x][i],y = lca[y][i]; if(x == y) return x;
return lca[x][0];
}
vector<int>vs[N],vt[N],st[N];
int ans[N],siz[N];
int stong[N << 1],ttong[N << 1];
void dfs(int u,int fa) {
int ks = stong[dep[u] + w[u]],kt = ttong[w[u] - dep[u] + N];
stong[dep[u]] += siz[u];
for(vector<int>::iterator it = st[u].begin();it != st[u].end();++it) ttong[*it]++; for(int i = head[u];i;i = e[i].nxt) {
int v = e[i].v;
if(v != fa) dfs(v,u);
} for(vector<int>::iterator it = vt[u].begin();it != vt[u].end();++it) ttong[*it]--; ans[u] = stong[dep[u] + w[u]] - ks + ttong[w[u] - dep[u] + N] - kt; for(vector<int>::iterator it = vs[u].begin();it != vs[u].end();++it) stong[*it]--; }
void main() {
for(int i = 1;i < n;++i) {
int u = read(),v = read();
add(u,v);add(v,u);
}
for(int i = 1;i <= n;++i) w[i] = read();
get_lca(1,0); for(int i = 1;i <= m;++i) {
int s = read(),t = read();
int k = LCA(s,t),len = dep[s] + dep[t] - dep[k] * 2;
vs[k].push_back(dep[s]);
vt[k].push_back(len - dep[t] + N);
st[t].push_back(len - dep[t] + N);
siz[s]++;
} dfs(1,0);
for(int i = 1;i <= n;++i) printf("%d ",ans[i]);
}
}
int main() {
n = read(),m = read();
if(n == 991) {BF1::main();return 0;}
if(n == 992) {BF2::main();return 0;}
if(n == 993) {BF3::main();return 0;}
if(n == 99994) {BF4::main();return 0;}
if(n == 99995) {BF5::main();return 0;}
if(n == 99996) {BF6::main();return 0;}
BF7::main();
return 0;
} /*
5 3
1 2
2 3
3 4
4 5
1 1 2 2 3
2 4
1 3
1 5 7 4
1 2
1 3
2 4
2 5
3 6
3 7
1 1 1 2 3 2 4
1 2
1 5
1 6
1 7 7 4
1 2
1 3
2 4
2 5
3 6
3 7
2 1 1 1 1 0 1
4 1
5 1
6 1
7 1
*/

Noip2016Day1T2 天天爱跑步的更多相关文章

  1. [NOIP2016-day1-T2]天天爱跑步running_题解

    题目来源:http://www.lydsy.com/JudgeOnline/problem.php?id=4719 镇楼图: noip滚粗后..订正的第一题. 题目大意: 有若干条路径在一棵树上,问每 ...

  2. NOIP2016Day1T2天天爱跑步(LCA+桶)

    据说是今年NOIP最难一题了...我还记得当时满怀期待心情点开Day1的题发现T2就不会了于是怀疑人生良久... 啊好像很多大爷都是用线段树合并写的,我怎么什么数据结构都不会啊呜呜呜... 题目大意就 ...

  3. UOJ261 【NOIP2016】天天爱跑步

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

  4. BZOJ4719 [Noip2016]天天爱跑步

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

  5. noip2016天天爱跑步

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

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

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

  7. [NOIP]2016天天爱跑步

    [NOIP]2016天天爱跑步 标签: LCA 树上差分 NOIP Description 小C同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.<天天爱跑步>是 ...

  8. NOIP2016 天天爱跑步 80分暴力

    https://www.luogu.org/problem/show?pid=1600 题目描述 小c同学认为跑步非常有趣,于是决定制作一款叫做<天天爱跑步>的游戏.«天天爱跑步»是一个养 ...

  9. [NOIp 2016]天天爱跑步

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

随机推荐

  1. OPENGL 坐标轴转换

    坐标轴 平移 旋转 缩放 重置坐标轴 矩阵操作 示例 1.坐标轴  OpenGL 使用的右手坐标系,从正面看原点,逆时针旋转被认为是正旋转. x轴:从左到右 y轴:从底部向上 z轴:从屏幕背向朝向前方 ...

  2. 【Beta阶段】第十二周Scrum会议

    [Beta阶段]第十二周Scrum会议 本次会议为第十二周第一次Scrum Meeting,会议对Beta阶段工作进行了总结,针对Beta阶段还未完成的问题进行了讨论. 会议时间为2019.12.3. ...

  3. 使用 Anydesk 5.1 TCP 通道(端口映射)功能从外网方便访问内网的 web/数据库等资源

    Anydesk 5.1 带来一个新的功能:TCP 通道,在家办公时,通过互联网进行远程桌面连接到公司电脑,可以将家用电脑的某个端口,映射到公司网络的某个电脑( IP + 端口),不局限于被远程桌面连接 ...

  4. Python的filter方法实现筛选功能

    filter方法可以实现筛选,第一个参数是一个函数,返回值是True或者False,第二个参数可以是str.tuple.list,将后面的参数依次传递给函数,依次判断结果,留下结果为 True的.比如 ...

  5. 「专题总结」LCT 2

    差不多理解板子之后,写了一些奇怪的题. 但是还是那个问题:树剖真好使. 魔法森林:mikufun说这个是傻逼题. 为了得到书法大家的真传,小 E 同学下定决心去拜访住在魔法森林中的隐士. 魔法森林可以 ...

  6. 关于中医的一段对话 [ZZ] -- 思维训练故事

    转载自新浪博客 网址: http://blog.sina.cn/dpool/blog/s/blog_9880df4201015khq.html?type=-1 关于中医的一段对话 2013-01-26 ...

  7. Git push error: http 411的解决方案总结

    目录 一.事故现场 二.事故原因 三.解决方案 一.事故现场 git push 的时候报错如下: 将分支推送到远程存储库时遇到错误:Git failed with a fatal error, the ...

  8. Spring Security从后台数据库查询实现登陆控制

    Spring Security框架是一个控制登陆的框架,通过配置文件获取后台的用户名及密码,进行比较进行登陆判断 使用步骤 1.导入依赖 <!-- 身份验证 --> <depende ...

  9. C++如何使用宏定义来简化代码性能测试 | cpp macro like function to implement a performance profiler

    本文首发于个人博客https://kezunlin.me/post/65dc693d/,欢迎阅读最新内容! cpp macro like function to implement a perform ...

  10. .net core 日常学习第一篇

    使用vs 2015 update3 版本,安装sdk:https://dotnet.microsoft.com/download  可以运行 .net core 1.x版 或者使用vs 2017及以上 ...