NOIP2016最难的一道题目,正解不会系列。。
然而那年每道题都有比较详细的分段范围,所以我们可以尝试拿到部分分。这里提供部分分为60分的做法。
Sample 1 2
只有当某个点时刻为0时才有可能观察到选手 因此我们先将初始状态每个点的选手数目统计下来 然后对每个点的时间遍历 如果时间为0输出该点选手数目 否则输出0
Sample 3 4
由于时间为0, 所以我们将初始状态每个点的选手数目统计下来后直接输出即可。
Sample 5
其实想到这个做法后可以用这个做法解决Sample 1 2 3 4。由于数据范围在1000以内,所以我们对于每个询问都从初始点爆搜,如果深度步数相同就给当前节点+1,注意终点特判。
Sample 6 7 8
数据范围变大了,但我们仍然有比较好的解决方法。由于是一条链,所以我们只需要把询问的起点和终点连边即可。然后我们对于每个点设x,y代表其往前或往后走t[i]所到达的结点。当符合范围内时,如果连边后该节点所到达的结点超过了询问的终止节点,那么肯定在t[i]的时间内能正好到达那个点,给那个点的答案+1即可。
Sample 9 10 11 12
由于都是从起点出发,我们可以记录下每个节点的深度,并开一个size数组记录每个点的子树内所包含的目标终点的个数。首先终点所在的点的size要初始化为1,然后对于时间等于深度的结点我们记录下其size值,dfs内size[x]+=size[y]
#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdlib>
using namespace std;
const int maxn=300010;
const int maxm=300010;
int n,m;
int head[maxn],nnext[maxm*2],to[maxm*2],t[maxn];
bool b[maxn];
int size[maxn];
int ob[maxn];
int tot;
int depth[maxn],fa[maxn];
struct player
{
int s;
int t;
}a[maxm];
void add(int x,int y)
{
tot++;
nnext[tot]=head[x];
head[x]=tot;
to[tot]=y;
}
void dfs(int x)
{
for(int i=head[x];i;i=nnext[i])
{
int y=to[i];
if(y==fa[x]) continue;
fa[y]=x;
depth[y]=depth[x]+1;
dfs(y);
}
}
void ddfs(int x,int step)
{
for(int i=head[x];i;i=nnext[i])
{
int y=to[i];
if(y==fa[x]) continue;
ddfs(y,step+1);
size[x]+=size[y];
}
if(t[x]==step)
{
ob[x]=size[x];
}
}
bool dfs1(int x,int fa,int y,int step)
{
if(x==y)
{
if(t[y]==step) ob[y]++;
return true;
}
for(int i=head[x];i;i=nnext[i])
{
int go=to[i];
if(go==fa) continue;
if(dfs1(go,x,y,step+1)==true)
{
if(t[x]==step) ob[x]++;
return true;
}
}
return false;
}
int main()
{
// freopen("running.in","r",stdin);
// freopen("running.out","w",stdout);
scanf("%d%d",&n,&m);
//sample 6 7 8
if(n==99994)
{
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
}
for(int i=1;i<=m;i++)
{
int s,t;
scanf("%d%d",&s,&t);
add(s,t);
}
for(int i=1;i<=n;i++)
{
int x=i-t[i];
int y=i+t[i];
if(x>=1)
{
for(int j=head[x];j;j=nnext[j])
{
if(to[j]>=i) ob[i]++;
}
}
if(y<=n)
{
for(int j=head[y];j;j=nnext[j])
{
if(to[j]<=i) ob[i]++;
}
}
}
for(int i=1;i<=n;i++)
{
printf("%d ",ob[i]);
}
return 0;
}
//sample 5
if(n==993)
{
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d %d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
}
for(int i=1;i<=m;i++)
{
int s,t;
scanf("%d %d",&s,&t);
dfs1(s,0,t,0);
}
for(int i=1;i<=n;i++)
{
printf("%d ",ob[i]);
}
return 0;
}
for(int i=1;i<=n-1;i++)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
add(y,x);
}
for(int i=1;i<=n;i++)
{
scanf("%d",&t[i]);
}
for(int i=1;i<=m;i++)
{
scanf("%d%d",&a[i].s,&a[i].t);
}
// sample 3 and 4
bool flag;
for(int i=1;i<=n;i++)
{
if(t[i]!=0) flag=true;
}
if(flag==false)
{
for(int i=1;i<=m;i++)
{
ob[a[i].s]++;
}
for(int i=1;i<=n;i++)
{
cout<<ob[i]<<' ';
}
return 0;
}
//sample 1 and 2
bool flag1;
for(int i=1;i<=m;i++)
{
if(a[i].s!=a[i].t) flag1=true;
}
if(flag1==false)
{
for(int i=1;i<=m;i++)
{
ob[a[i].s]++;
}
for(int i=1;i<=n;i++)
{
if(t[i]!=0) cout<<"0"<<' ';
else cout<<ob[i]<<' ';
}
return 0;
}
// sample 9 10 11 12
bool flag2;
for(int i=1;i<=m;i++)
{
if(a[i].s!=1) flag2=true;
}
if(flag2==false)
{
depth[1]=0;
dfs(1);
for(int i=1;i<=m;i++)
{
size[a[i].t]++;
}
ddfs(1,0);
for(int i=1;i<=n;i++)
{
printf("%d ",ob[i]);
}
return 0;
}
fclose(stdin);
fclose(stdout);
return 0;
}