NOIP2024模拟赛10:热烈张扬
T1
-
一句话题意:给定一颗树和两个玩家的起点 \(a,b\) 和各自的移动速度 \(da,db\).问:如果二人均以最优策略移动,问最后谁是赢家(先走到对方当前位置)
-
标签:LCA,思维,博弈
-
不妨设 \(a\) 是速度快的,\(b\) 是速度慢的。
-
结论一:若二者初始距离 \(\le\) 先手的初始速度,则先手第一步就赢.
除此以外:
-
结论2:\(a\) 总是可以通过若干步同 \(b\) 调整距离,使得最终 \(a\) 可以跳到 \(b\), 但 \(b\) 跳不到 \(a\).【这很好理解】
-
结论3:若两者速度相同,平局.
-
时间复杂度: \(O(T(NlogN+QlogN))\)
#include<bits/stdc++.h>
#define F(i,l,r) for(int i(l);i<=r;++i)
#define G(i,r,l) for(int i(r);i>=l;--i)
using namespace std;
using ll = long long;
char buf[100],*p1=buf,*p2=buf;
inline int gc(){return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,100,stdin),p1==p2)?EOF:*p1++;}
inline int rd(){
int x=0; char ch;
while(!isdigit(ch=gc()));
do x=(x<<3)+(x<<1)+(ch^48); while(isdigit(ch=gc()));
return x;
}
const int N=2e6+5;
int fa[N][22],dep[N];
int n,q,d,t;
vector<int> G[N];
void ini(int u,int f){
fa[u][0]=f;
dep[u]=dep[f]+1;
F(i,1,20) fa[u][i]=fa[fa[u][i-1]][i-1];
for(auto v:G[u]){
if(v==f) continue;
ini(v,u);
}
}
int lca(int x,int y){
if(dep[x]<dep[y]) swap(x,y);
G(i,20,0) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];
if(x==y) return x;
G(i,20,0) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
return fa[x][0];
}
int calc(int x,int y){
int p=lca(x,y);
return dep[x]+dep[y]-2*dep[p];
}
signed main(){
// freopen("game.in","r",stdin);
// freopen("game.out","w",stdout);
d=rd(),t=rd();
while(t--){
n=rd(),q=rd();
F(i,1,n-1){
int u=rd(),v=rd();
G[u].emplace_back(v);
G[v].emplace_back(u);
}
ini(1,0);
while(q--){
int a=rd(),b=rd(),da=rd(),db=rd();
int dis=calc(a,b);
if(da>db) puts("Zayin");
else if(da==db){
if(dis<=da) puts("Zayin");
else puts("Draw");
}
else{
if(dis<=da) puts("Zayin");
else puts("Ziyin");
}
}
F(i,1,n) {
G[i].clear();
}
}
return 0;
}
- 总结:
- 看数据范围这么大,结论应该往简单了猜,否则肯定T掉!
- 关于 题目条件"最优策略" 的使用:往往是在 "特定一方尽量优的情况下,保证另一方被动中的最优".