bzoj4134 (sg函数,线段树合并(trie))

来源:互联网 发布:2008年好听的网络歌曲 编辑:程序博客网 时间:2024/04/20 19:43

 

trie合并,加sg函数。。。

 

这道题体现了dp思想处理博弈论问题,同时发现许多的书上信息合并问题可以考虑线段树合并。

也体现了,trie处理xor问题,也体现了trie处理mex问题。

 

 

 

#include<cstdio>#include<cmath>#include<cstring>#include<cstdlib>#include<algorithm>#include<stack>using namespace std;const int N=100005;const int D=19;int n;int c[N];int head[N],tot,pre[N*2],to[N*2];void addedge(int u,int v){to[++tot]=v;pre[tot]=head[u];head[u]=tot;}int dp[N];int num,rt[N],ch[N*41][2],rev[N*41],val[N*41];void build(int &u,int tmp,int D) {if (u==0) u=++num;if (D==-1) {val[u]=1;return ;}build(ch[u][tmp>>D&1],tmp,D-1);}void down(int u,int D) {rev[ch[u][0]]^=rev[u];rev[ch[u][1]]^=rev[u];if (rev[u]&(1<<D)) swap(ch[u][0],ch[u][1]);rev[u]=0;}int merge(int u,int v,int D) {if (!u||!v) return v+u;if (D==-1) return val[u]=1,u;down(u,D);down(v,D);int tmp=++num;ch[tmp][0]=merge(ch[u][0],ch[v][0],D-1);ch[tmp][1]=merge(ch[u][1],ch[v][1],D-1);val[tmp]=val[ch[tmp][0]]&&val[ch[tmp][1]];return tmp;}int get_sg(int u){int ans=0;for (int i=D;i>=0;i--) {down(u,i);if (val[ch[u][0]]==0) u=ch[u][0];else u=ch[u][1],ans+=(1<<i); } return ans;}int h[N];void dfs(int u,int fa){for (int i=head[u];i;i=pre[i]) if (to[i]!=fa)dfs(to[i],u),h[u]^=dp[to[i]];if (!c[u]) build(rt[u],h[u],D);for (int i=head[u];i;i=pre[i]) if (to[i]!=fa) {rev[rt[to[i]]]^=h[u]^dp[to[i]];rt[u]=merge(rt[u],rt[to[i]],D);}dp[u]=get_sg(rt[u]);}int ans[N],cnt;void find_ans(int u,int fa,int now){now^=dp[u]^h[u];if (!now&&!c[u]) ans[++cnt]=u;for (int i=head[u];i;i=pre[i])if (fa!=to[i])  find_ans(to[i],u,now);}int main(){scanf("%d",&n);for (int i=1;i<=n;i++) scanf("%d",&c[i]);int u,v;for (int i=1;i<n;i++) {scanf("%d%d",&u,&v);addedge(u,v);addedge(v,u);}dfs(1,0);if (dp[1]==0) {printf("-1\n");return 0;}find_ans(1,0,dp[1]);sort(ans+1,ans+cnt+1);for (int i=1;i<=cnt;i++) printf("%d\n",ans[i]);return 0;}


 

0 0
原创粉丝点击