【题目大意】:给出一棵n个结点的树,两个人一起走,轮流决策。Alice目的是使最后距离最小,Bob则要最大。问最终走的距离能否满足区间[L,R](需要走到最后不能走,所以Alice不能不选就结束了)
【解题思路】:第一次见到这道题是去年的暑假,当初一直把它当初博弈去找必胜态和必败态,然后徒劳无功。
下午队友把这道题切了,G++交必须用恶心的输入外挂....回来之后,顺手自己也把它写了一下,有向图很好写,O(n)而已。
我们设dist[u]记录0到u的距离,dp[u]记录u这点开始最终走的距离。
在dist[u]+dp[v]+w也就是0到u的距离,加上v开始的距离,和u到v的距离是在[L,R]之间,则进行状态的转移,也就是Alice会取min(dp[u],dp[v]+w),Bob会取max(dp[u],dp[v]+w)...
注释部分是输入挂...
【代码】:
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <queue>
#include <cmath>
#include <string>
#include <cctype>
#include <map>
#include <iomanip>
using namespace std;
#define eps 1e-8
#define pi acos(-1.0)
#define inf 1<<30
#define linf 1LL<<60
#define pb push_back
#define lc(x) (x << 1)
#define rc(x) (x << 1 | 1)
#define lowbit(x) (x & (-x))
#define ll long long
int n,le,ri;
int tot,eh[600000];
int dp[500500],dist[500500];
struct Edge {
int v,w,next;
}et[600000];
/*int getint(){
char c=getchar();
int t=0;
while (c<'0' || c>'9') {
c=getchar();
}
while (c>='0' && c<='9') {
t=t*10+c-'0';
c=getchar();
}
return t;
}*/
void init() {
tot=0;
memset(eh,-1,sizeof(eh));
}
void addedge(int u,int v,int w) {
Edge e={v,w,eh[u]};
et[tot]=e;
eh[u]=tot++;
}
void dfs(int u,int who) {
dp[u]=0;
for (int i=eh[u]; i!=-1; i=et[i].next) {
int v=et[i].v,w=et[i].w;
dist[v]=dist[u]+w;
dfs(v,!who);
if(dist[u]+dp[v]+w>=le && dist[u]+dp[v]+w<=ri) {
if(who || dp[u]==0) dp[u]=max(dp[u],dp[v]+w);
else dp[u]=min(dp[u],dp[v]+w);
}
}
return ;
}
int main() {
int u,v,w,i;
while(~scanf("%d%d%d",&n,&le,&ri)) {
init();
memset(dist,0,sizeof(dist));
for(int i=1; i<n; i++) {
//u=getint(); v=getint(); w=getint();
scanf("%d%d%d",&u,&v,&w);
addedge(u,v,w);
}
dfs(0,1);
if(ri<le || dp[0]<le || dp[0]>ri) printf("Oh, my god!\n");
else printf("%d\n",dp[0]);
}
return 0;
}