题解 CF1149E 【Election Promises】

· · 题解

首先如果没有任意地去改变后继节点的权值的话,这道题就是一个nim游戏的板子。

有的话首先考虑一下分组,分组的过程是这样:

考虑这样分组的特点:

那么考虑每一个组内所有点的异或和,设其为val[i]

那么考虑发现一下val的一些性质:

那么我们通过上面两个性质可以知道:

那么通过上面的分析,对于初始局面,只要有一个组的val0,那么这个局面就是先手必胜,否则就是先手必败。

至于输出方案的话,我们只需要对于那个标号最大的val不为0的组找到一个能将val降成0的点降成0,然后将它的后继节点修改即可。

复杂度O(n)

code:

#include<bits/stdc++.h>
#define maxn 200010
using namespace std;
typedef long long ll;
ll read()
{
    ll x=0,f=1;
    char ch=getchar();
    while(ch-'0'<0||ch-'0'>9){if(ch=='-') f=-1;ch=getchar();}
    while(ch-'0'>=0&&ch-'0'<=9){x=x*10+ch-'0';ch=getchar();}
    return x*f;
}
int n,m,top,mx;
int head[maxn],nxt[maxn],to[maxn],tot;
void add(int u,int v)
{
    tot++;
    nxt[tot]=head[u];
    head[u]=tot;
    to[tot]=v;
}
ll a[maxn],val[maxn];
int deg[maxn],p[maxn],vis[maxn],id[maxn];
queue<int>q;
void top_sort()
{
    for(int i=1;i<=n;i++)
      if(!deg[i])  q.push(i);
    while(q.size())
    {
        int now=q.front();q.pop();
        p[++top]=now;
        for(int i=head[now];i;i=nxt[i])
        {
            deg[to[i]]--;
            if(!deg[to[i]])  q.push(to[i]);
        }
    }
    for(int i=n;i>=1;i--)
    {
        int x=p[i];
        for(int j=head[x];j;j=nxt[j])  vis[id[to[j]]]=1;
        while(vis[id[x]])  id[x]++;
        val[id[x]]^=a[x];mx=max(mx,id[x]);
        for(int j=head[x];j;j=nxt[j])  vis[id[to[j]]]=0;
    }
}
int main()
{
    n=read();m=read();
    for(int i=1;i<=n;i++)  a[i]=read();
    for(int i=1;i<=m;i++)
    {
        int q=read(),w=read();
        add(q,w);deg[w]++;
    }
    top_sort();
    int pos=-1;
    for(int i=0;i<=mx;i++)
      if(val[i])  pos=i;
    if(pos==-1)  return puts("LOSE"),0;
    puts("WIN");
    for(int i=1;i<=n;i++)
    {
        if(id[i]==pos)
        {
            if((val[id[i]]^a[i])>a[i])  continue;
            a[i]^=val[id[i]];val[id[i]]=0;
            for(int j=head[i];j;j=nxt[j])
              a[to[j]]^=val[id[to[j]]],val[id[to[j]]]=0;
        }
    }
    for(int i=1;i<=n;i++)  printf("%lld ",a[i]);
    puts("");
    return 0;
}