zoukankan      html  css  js  c++  java
  • 【bzoj4730】 Alice和Bob又在玩游戏

    http://www.lydsy.com/JudgeOnline/problem.php?id=4730 (题目链接)

    题意

      给出一个森林,两个人轮流操作,每次把一个节点以及它的祖先全部抹去,无节点可以抹去是算输,问是否存在先手必胜策略。

    Solution

      trie树合并,其实就是线段树合并。

      bzoj4134的简单版:http://blog.csdn.net/werkeytom_ftd/article/details/50958988

    细节

      二进制小心写错

    代码

    // bzoj4730
    #include<algorithm>
    #include<iostream>
    #include<cstdlib>
    #include<cstring>
    #include<cstdio>
    #include<cmath>
    #include<queue>
    #define LL long long
    #define inf (1ll<<60)
    #define Pi acos(-1.0)
    #define free(a) freopen(a".in","r",stdin),freopen(a".out","w",stdout);
    using namespace std;
    
    const int maxn=1000010;
    int head[maxn],vis[maxn],SG[maxn],rt[maxn],n,m,sz,cnt,bin[30];
    struct edge {int to,next;}e[maxn<<1];
    struct node {
    	int ls,rs,tag,size;
    	void Init() {ls=rs=tag=size=0;}
    }tr[maxn<<2];
    
    void link(int u,int v) {
    	e[++cnt]=(edge){v,head[u]};head[u]=cnt;
    	e[++cnt]=(edge){u,head[v]};head[v]=cnt;
    }
    void pushdown(int k,int x) {
    	if (tr[k].tag&bin[x-1]) swap(tr[k].ls,tr[k].rs);
    	tr[tr[k].ls].tag^=tr[k].tag;
    	tr[tr[k].rs].tag^=tr[k].tag;
    	tr[k].tag=0;
    }
    void insert(int &k,int x,int y) {
    	if (!k) k=++sz;tr[k].Init();
    	tr[k].size=1;if (!y) return;
    	x&bin[y-1] ? insert(tr[k].rs,x,y-1) : insert(tr[k].ls,x,y-1);
    }
    int merge(int x,int y,int k) {
    	if (!x || !y) return x|y;
    	pushdown(x,k);pushdown(y,k);
    	tr[x].ls=merge(tr[x].ls,tr[y].ls,k-1);
    	tr[x].rs=merge(tr[x].rs,tr[y].rs,k-1);
    	tr[x].size=tr[tr[x].ls].size+tr[tr[x].rs].size+(k==0);
    	return x;
    }
    void dfs(int x,int fa) {
    	int t=0;vis[x]=1;  //t表示儿子的SG异或和
    	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) {
    			dfs(e[i].to,x);
    			t^=SG[e[i].to];
    		}
    	insert(rt[x],t,20);  //此时插入的是删除x所得到的后继状态的SG值
    	for (int i=head[x];i;i=e[i].next) if (e[i].to!=fa) {
    			tr[rt[e[i].to]].tag=t^SG[e[i].to];  //异或上除e[i].to以外其它儿子节点子树的SG
    			rt[x]=merge(rt[x],rt[e[i].to],20);
    		}
    	for (int i=20,p=rt[x];i;i--) {
    		pushdown(p,i);
    		if (tr[tr[p].ls].size<bin[i-1]) p=tr[p].ls;
    		else SG[x]|=bin[i-1],p=tr[p].rs;
    	}
    }
    int main() {
    	bin[0]=1;for (int i=1;i<=20;i++) bin[i]=bin[i-1]<<1;
    	int T;scanf("%d",&T);
    	while (T--) {
    		sz=0;cnt=0;
    		for (int i=1;i<=n;i++) vis[i]=rt[i]=SG[i]=head[i]=0;
    		scanf("%d%d",&n,&m);
    		for (int u,v,i=1;i<=m;i++) {
    			scanf("%d%d",&u,&v);
    			link(u,v);
    		}
    		int ans=0;
    		for (int i=1;i<=n;i++)
    			if (!vis[i]) dfs(i,0),ans^=SG[i];
    		puts(ans ? "Alice" : "Bob");
    	}
    	return 0;
    }
    
  • 相关阅读:
    php中__construct()和__initialize()的区别
    js的栈内存和堆内存
    CC攻击原理及防范方法
    html页面调用js文件里的函数报错onclick is not defined处理方法
    yii2深入理解之内核解析
    Scala Data Structure
    Scala Basis
    【MySql】牛客SQL刷题(下)
    【Flume】知识点整理
    【kafka】生产者API
  • 原文地址:https://www.cnblogs.com/MashiroSky/p/6443160.html
Copyright © 2011-2022 走看看