题目描述
小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
说明
【样例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
会因为栈溢出而崩溃; 如果使用了上述命令后运行该程序,该程序则不会崩溃。
特别地, 当你打开多个终端时, 它们并不会共享该命令, 你需要分别对它们
运行该命令。
请注意, 调用栈占用的空间会计入总空间占用中, 和程序其他部分占用的内
存共同受到内存限制。
思路
用lca算法,找到最近公共祖先,然后可以查出s到t的最短路径(也可以用图上最短路径做法,但是毕竟这是在树上,lca显得更合适省时),于是可以找出路上每个点是在哪个时刻经过的,如果这个时刻与观察员出现的时刻相同,则观察员能观察到的数量就+1
(郁闷ing,第一次打lca,几乎用了一个上午的时间,却因为超时只得了25分。。)
//怎么才能不超时!! #include<iostream> #include<vector> #include<cstring> #include<cstdio> using namespace std; vector<int>e[300000]; int dep[300000],f[300000][25]; int n,m,lca,num; int point[300000]; int ans[300000]; int cmp[300000]; int qread() { int x=0,j=1; char ch=getchar(); while(ch>'9'||ch<'0'){if(ch=='-')j=-1;ch=getchar();} while(ch<='9'&&ch>='0'){x=x*10+(int)(ch-'0');ch=getchar();} return x*j; } void find_deep(int pos,int pre) { for(int i=0;i<e[pos].size();i++) { if(e[pos][i]==pre)continue; else{ dep[e[pos][i]]=dep[pos]+1; f[e[pos][i]][0]=pos; find_deep(e[pos][i],pos); } } } void yuchuli() { for(int i=1;(1<<i)<=n;i++) { for(int j=1;j<=n;j++) { f[j][i]=f[f[j][i-1]][i-1]; } } } void show(int lca,int ed) { if(ed==lca)return; else show(lca,f[ed][0]); cmp[++num]=ed; } void dic(int start,int end) { bool flag=0;int a=start,b=end; if(dep[start]<dep[end])swap(a,b),flag=1; for(int i=20;i>=0;i--) if(dep[f[a][i]]>=dep[b]) a=f[a][i]; /*int t=dep[a]-dep[b]; for(int i=0;i<=20;i++){ if((1<<i)&t)a=f[a][i]; }*/ if(a==b) { lca=a; } else{ for(int i=20;i>=0;i--) if(f[a][i]!=f[b][i]) { a=f[a][i]; b=f[b][i]; } lca=f[a][0]; } int st,ed;st=start,ed=end; memset(cmp,0,sizeof(cmp)); num=0; cmp[++num]=st; while(st!=lca) { cmp[++num]=f[st][0]; st=f[st][0]; } show(lca,ed); //for(int i=1;i<=num;i++)cout<<cmp[i]<<' ';cout<<endl; for(int i=1;i<=num;i++) if(point[cmp[i]]==i-1)ans[cmp[i]]++; } int main() { n=qread();m=qread(); int from,to; for(int i=1;i<n;i++) { from=qread();to=qread(); e[from].push_back(to); e[to].push_back(from); } for(int i=1;i<=n;i++)cin>>point[i]; dep[1]=1; find_deep(1,-1); yuchuli(); //for(int i=1;i<=n;i++)cout<<dep[i]<<' ';cout<<endl; for(int i=1;i<=m;i++) { lca=0; int start,end; start=qread();end=qread(); dic(start,end); } for(int i=1;i<=n;i++) cout<<ans[i]<<' '; cout<<endl; }