4719: [Noip2016]天天爱跑步
Time Limit: 40 Sec Memory Limit: 512 MB
Submit: 1464 Solved: 490
[Submit][Status][Discuss]
Description
Input
Output
输出1行N 个整数,第个整数表示结点的观察员可以观察到多少人。
Sample Input
2 3
1 2
1 4
4 5
4 6
0 2 5 1 2 3
1 5
1 3
2 6
Sample Output
HINT
题目链接:
http://www.lydsy.com/JudgeOnline/problem.php?id=4719
Solution
刚开始学OI的时候就看过这道题。。。当时是贴代码过的。。。。
记得好像是用树链剖分。。不记得了。。反正很长。。。
现在快要noip了。。。把往年的题目拿出来看一下,算是临近noip的梳理吧。。。。。
好多废话
进入正题。。。。。
首先每个人都要走最短路径。。。马上想到LCA。。。不然还能有什么。。。
每个人分别统计显然是不行的,不过似乎可以根据特殊情况水很多分。。
于是想到差分。。
假设第 i 个人的起点为 Si ,终点为 Ti 。。LCA ( Si ,Ti ) = rt
每条线段长度都是 1 ,故路径长度与深度有关。。。
于是路径就可以分成两部分:Si -> rt 和 rt ->Ti
两条路径分开统计。。。
在向上的路径中,比如一个起点 Si ,深度为 dep [ Si ] ,
那么可以在遍历到Si的时候 U [ dep [ Si ] ] ++;
然后在到达 rt 的父亲的时候 U [ dep [ Si ] ] --; (U [ i ]表示某一方向路径的总值)
向下的路径用一样的方法。。。但这样rt 的统计会有重复。。
所以两次统计中要有一次在 rt 的时候就 U [ dep [ Si ] ] - - ;
这样就可以了,虽然分析很长但代码不是很长。。。。
注意在BZOJ上提交不能有末尾空格。。。害我PE了一发。。。
代码
#include<cstdio>
#include<cstring>
#include<cmath>
#include<algorithm>
#include<iostream>
#define N 400000
using namespace std;
inline int Read(){
int x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int n,m,cnt=0;
int fa[N][22];
int hed[N],w[N],dep[N],ans[N],U[N],D[N<<1];
struct edge{
int r,nxt;
}e[N<<1];
struct node{
int u,w;
};
vectore1[N],e2[N<<1];
void insert(int u,int v){
e[++cnt]=(edge){v,hed[u]};hed[u]=cnt;
e[++cnt]=(edge){u,hed[v]};hed[v]=cnt;
}
void dfs1(int x,int F){
for(int i=1;(1<<i)<=dep[x];i++)
fa[x][i]=fa[fa[x][i-1]][i-1];
for(int i=hed[x];i;i=e[i].nxt)
if(e[i].r!=F){
dep[e[i].r]=dep[x]+1;
fa[e[i].r][0]=x;
dfs1(e[i].r,x);
}
}
int lca(int u,int v){
if(dep[u]<dep[v])swap(u,v);
int d=dep[u]-dep[v];
for(int i=0;(1<<i)<=d;i++)
if((1<<i)&d)
u=fa[u][i];
if(u==v)return u;
for(int i=20;i>=0;i--){
if((1<<i)>dep[u] || fa[u][i]==fa[v][i])continue;
u=fa[u][i];v=fa[v][i];
}
return fa[u][0];
}
void dfs2(int x,int F){
ans[x]-=U[w[x]+dep[x]];
ans[x]-=D[w[x]-dep[x]+n];
for(int i=0;i<e1[x].size();i++)
U[e1[x][i].u]+=e1[x][i].w;
for(int i=0;i<e2[x].size();i++)
D[e2[x][i].u+n]+=e2[x][i].w;
for(int i=hed[x];i;i=e[i].nxt)
if(e[i].r!=F)
dfs2(e[i].r,x);
ans[x]+=U[w[x]+dep[x]]+D[w[x]-dep[x]+n];
}
int main(){
int u,v,rt;
n=Read();m=Read();
for(int i=1;i<n;i++){
u=Read();v=Read();
insert(u,v);
}
for(int i=1;i<=n;i++)
w[i]=Read();
dfs1(1,0);
for(int i=1;i<=m;i++){
u=Read();v=Read();
rt=lca(u,v);
e1[u].push_back((node){dep[u],1});
e1[rt].push_back((node){dep[u],-1});
e2[v].push_back((node){dep[u]-(dep[rt]<<1),1});
e2[fa[rt][0]].push_back((node){dep[u]-(dep[rt]<<1),-1});
}
dfs2(1,0);
for(int i=1;i<n;i++)
printf("%d ",ans[i]);
printf("%d",ans[n]);
return 0;
}
This passage is made by Iscream-2001.