Luogu P3727 曼哈頓計劃E 點分治+hash

題目:

  P3727曼哈頓計劃Enode

分析:

  大長題面容易給人一種不可作的錯覺,可是這題考的知識點都是咱們熟悉的。c++

  稍加分析咱們能夠獲得,咱們能夠把每一個點當成一個單獨的遊戲,若是k=1,就是簡單的nim遊戲,這樣,當多個遊戲放在一塊兒的時候,咱們就能夠根據一條鏈的權值異或和來判斷必勝必敗。ide

  這個給咱們啓發,根據SG定理(應該是這個定理?)當咱們選一條鏈,根據這條鏈上全部點的SG函數的異或和,能夠判斷勝負。函數

  因此咱們能夠對於每一個k想辦法求點的sg函數,就能夠用點分治解決這個題。spa

  怎麼求sg函數?(打表找規律啊),或者若是你有辦法推也能夠。code

 代碼:blog

 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 }
博弈論+點分治
相關文章
相關標籤/搜索