Luogu P3727 曼哈顿计划E 点分治+hash

题目:

  P3727曼哈顿计划E

分析:

  大长题面容易给人一种不可做的错觉,但是这题考的知识点都是我们熟悉的。

  稍加分析我们可以得到,我们可以把每个点当成一个单独的游戏,如果k=1,就是简单的nim游戏,这样,当多个游戏放在一起的时候,我们就可以根据一条链的权值异或和来判断必胜必败。

  这个给我们启发,根据SG定理(应该是这个定理?)当我们选一条链,根据这条链上所有点的SG函数的异或和,可以判断胜负。

  所以我们可以对于每个k想办法求点的sg函数,就可以用点分治解决这个题。

  怎么求sg函数?(打表找规律啊),或者如果你有办法推也可以。

 代码:

 1 #include<bits/stdc++.h>
 2 #define ms(a,x) memset(a,x,sizeof(a))
 3 using namespace std;
 4 const int N=30005,M=1e7;
 5 struct node{int y,nxt;}e[N*2];
 6 int t,n,k,s,c=0,hs,pd,nt,h[N];
 7 int w[N],siz[N],vis[N],tp[N],tt[N];
 8 void add(int x,int y){
 9     e[++c]=(node){y,h[x]};h[x]=c;
10     e[++c]=(node){x,h[y]};h[y]=c;
11 } int sg1(int x){return x;}
12 int sg2(int x){return (x+1)%(s+1)?x&1:2;}
13 int sg3(int x){return x/s;}
14 int sg4(int x){
15     switch(x%4){
16         case 0: return x-1;
17         case 3: return x+1;
18         default : return x;
19     }
20 } void init(){
21     ms(h,0);ms(vis,0);c=0;
22 } void gs(int x,int fa){
23     siz[x]=1;
24     for(int i=h[x],y;i;i=e[i].nxt)
25     if((y=e[i].y)!=fa&&!vis[y]) 
26     gs(y,x),siz[x]+=siz[y];
27 } int gg(int x,int fa){
28     for(int i=h[x],y;i;i=e[i].nxt)
29     if((y=e[i].y)!=fa&&!vis[y]&&siz[y]>=hs)
30     return gg(y,x);return x;
31 } void dfs(int x,int fa,int o){
32     tt[nt]=x;tp[nt++]=o;
33     for(int i=h[x],y;i;i=e[i].nxt)
34     if((y=e[i].y)!=fa&&!vis[y]) dfs(y,x,o^w[y]);
35 } struct Hash{
36     static const int P1=100003,P2=100069;
37     int h1(int x){return x%P1;}
38     int h2(int x){return x%P2;}
39     int t1[P1],t2[P2],st[N],top;
40     Hash(){ms(t1,-1);ms(t2,-1);}
41     int find(int x){
42         return t1[h1(x)]==x||t2[h2(x)]==x;
43     } void insert(int x){
44         if(find(x)) return ;
45         int h=h2(x);st[top++]=x;
46         if(t2[h]==-1) t2[h]=x;
47         else while(~x){
48             h=h1(x);swap(x,t1[h]);
49             if(x==-1) return ;
50             h=h2(x);swap(x,t2[h]);
51         }
52     } void del(int x){
53         if(t1[h1(x)]==x) t1[h1(x)]=-1;
54         else t2[h2(x)]=-1;
55     } void clear(){
56         while(top) del(st[--top]);
57     }
58 }H;void dc(int x){
59     gs(x,0);hs=siz[x]>>1;int g;
60     g=gg(x,0);vis[g]=1;H.insert(0);
61     for(int i=h[g],y;i;i=e[i].nxt)
62     if(!vis[y=e[i].y]){
63         nt=0;dfs(y,0,w[y]);
64         for(int j=0;j<nt;j++)
65         if(H.find(w[g]^tp[j]))
66         {pd=1;break;}
67         for(int j=0;j<nt;j++)
68         H.insert(tp[j]);
69     } H.clear();
70     for(int i=h[g],y;i&&!pd;i=e[i].nxt)
71     if(!vis[y=e[i].y]) dc(y);return ;
72 } int main(){
73     scanf("%d",&t);while(t--){
74         init();scanf("%d",&n);
75         for(int i=1,y,x;i<n;i++)
76         scanf("%d%d",&x,&y),add(x,y);
77         for(int i=1;i<=n;i++) 
78         scanf("%d",&w[i]);scanf("%d",&k);
79         int (*sg)(int);
80         if(k==1) sg=sg1;
81         else if(k==2) scanf("%d",&s),sg=sg2;
82         else if(k==3) scanf("%d",&s),sg=sg3;
83         else sg=sg4;pd=0;
84         for(int i=1;i<=n;i++)
85         if(!(w[i]=sg(w[i]))) pd=1;
86         if(!pd) dc(1);
87         puts(pd?"Mutalisk ride face how to lose?":
88         "The commentary cannot go on!");
89     } return 0;
90 }
博弈论+点分治

 

posted @ 2019-02-27 16:10  杜宇一声  阅读(191)  评论(0编辑  收藏  举报