矿物运输「CSP多校联考 2019」
题意
在某个不知名的行星上蕴含着大量冰晶矿,\(Jim\)和他的好兄弟\(Swan\)自然不能放过这个赚钱的好机会。
\(Jim\)在整个星球上开掘树型矿洞,每个矿坑之间都有矿道相连。
\(Jim\)和\(Swan\)在每个矿坑开采了大量的矿石,现在他们面临一个新的问题,怎么把所有的矿石运出去。已知,矿坑与矿坑之间形成了有向的树形结构,即除0号矿坑以外每个矿坑都有与其相连的父亲矿坑。\(Jim\)总共开采了n个矿坑并将其从0到n编号 ,每个矿坑都存有\(val[i]\)个单位的矿石。
\(Jim\)和\(Swan\)每次操作都可以从某个矿坑移动至少1个单位的矿石到其父亲矿坑。\(Jim\)和\(Swan\)决定比试一下,由\(Jim\)开始轮流操作,最后不能操作的人输。\(Jim\)偷偷的找到了你,他想知道在两人都采取最优策略的情况下是否\(Jim\)能够赢得这场比试。
思路
博弈论题目≈你做不出来但是人人都会的题
可以把树看为很多个链,然后每一个链都是奇数位异或,所以最后相当于对深度为奇数的点值异或,如果为0就会输,否则胜利。
代码
#include <bits/stdc++.h>
using namespace std;
namespace StandardIO {
template<typename T>inline void read (T &x) {
x=0;T f=1;char c=getchar();
for (; c<'0'||c>'9'; c=getchar()) if (c=='-') f=-1;
for (; c>='0'&&c<='9'; c=getchar()) x=x*10+c-'0';
x*=f;
}
template<typename T>inline void write (T x) {
if (x<0) putchar('-'),x*=-1;
if (x>=10) write(x/10);
putchar(x%10+'0');
}
}
using namespace StandardIO;
namespace Project {
const int N=300300;
int T;
int n,ans,fa;
vector<int> G[N];
int val[N];
void dfs (int now,int fa,int dep) {
if (dep&1) ans^=val[now];
for (register int i=0; i<G[now].size(); ++i) {
int to=G[now][i];
if (to==fa) continue;
dfs(to,now,dep+1);
}
}
inline void MAIN () {
read(T);
while (T--) {
read(n),ans=0;
for (register int i=0; i<=n; ++i) {
G[i].clear();
}
for (register int i=1; i<n; ++i) {
read(fa);
G[i].push_back(fa),G[fa].push_back(i);
}
for (register int i=0; i<n; ++i) read(val[i]);
dfs(0,-1,0);
if (ans) puts("win");
else puts("lose");
}
}
}
int main () {
// freopen("ore.in","r",stdin);
// freopen("ore.out","w",stdout);
Project::MAIN();
}