Luogu P3727 曼哈顿计划E 点分治+hash
题目:
分析:
大长题面容易给人一种不可做的错觉,但是这题考的知识点都是我们熟悉的。
稍加分析我们可以得到,我们可以把每个点当成一个单独的游戏,如果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 }