這道題我第一眼看,嗯??博弈論?仍是樹上的?我好像不會啊。。。可是一想某人的話,感受這個應該也不會太難,可能有規律php
因而我就從樣例開始仔細思考找規律,第一個樣例應該是看不出來啥,但第二個內容量就比較豐富了。但我模擬完樣例二依舊沒發現什麼,難道這道題真要建個線段樹什麼的??接着我把關注點放到了輸出上,輸出只有兩種,那是否是應該存在某種奇偶關係?仍是要先考慮鏈的狀況,由於從無根樹上的一個點出發遍歷就至關於走幾條鏈(好像樹的問題大部分都跟鏈有關)。下面模擬一下
首先要注意到題目中的暗示,每次都要找一個到父親節點權值爲1的點,這就說明了這個問題的限制,它總會結束。先不考慮修改,若是以1爲根,不難看出女孩會贏,其中一種走法是
固然也有別的走法,但總會是女生贏。
若是以2爲根呢?不可貴出仍是女孩贏,其中一種走法爲
那麼是否是圖中邊權爲1的邊數爲偶數時,就是女生贏呢?仍舊以2爲根,咱們在4後邊再跟一個節點。
會發現這樣仍是女生贏。
那在根節點2後邊跟這個節點呢?
這時候再去模擬就會發現是男生贏了。因此咱們猜想,讓女生贏的並非圖中邊權爲1的邊數,而是根節點周圍邊權爲1的邊數,根據這個大膽的猜想,我寫出了下面的代碼,好像還白寫了一個加邊函數。若是你去用樣例測試,發現是對的,因此我興奮的交了上去,WA函數
#include<cstdio> #include<cstring> using namespace std; const int N=4e4+10; struct Edge{ int to,nxt,val; }e[N<<1]; int Head[N],len; void Ins(int a,int b,int c){ e[++len].to=b;e[len].val=c; e[len].nxt=Head[a];Head[a]=len; } int cnt[N]; int main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); memset(cnt,0,sizeof(cnt)); for(int i=1;i<n;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); cnt[a]+=c; cnt[b]+=c; } for(int i=1;i<=m;i++){ int op,x,y,z; scanf("%d",&op); if(op==1){ scanf("%d%d%d",&x,&y,&z); if(z==1)cnt[x]++,cnt[y]++; else cnt[x]--,cnt[y]--; } else { scanf("%d",&x); if(cnt&1)printf("Girls win!\n"); else printf("Boys win!\n"); } } } }
既然這個代碼過了樣例,就說明它應該不是偶然,因此應該是我少考慮了什麼。再回去讀了一邊題,發現題中並無說當\(op==1\)時,變換的權值與原來的權值相等,也就是說若是我每次都把1變爲0,0變爲1,那麼我上邊的代碼是能夠的,也就是樣例狀況,但問題就出在它多是1變爲1,0變爲0,因此每次必須掃描一邊根周圍的邊權之和,即下邊的代碼。測試
#include<cstdio> #include<cstring> using namespace std; const int N=4e4+10; struct Edge{ int to,nxt,val; }e[N<<1]; int Head[N],len; void Ins(int a,int b,int c){ e[++len].to=b;e[len].val=c; e[len].nxt=Head[a];Head[a]=len; } int main(){ int t; scanf("%d",&t); while(t--){ int n,m; scanf("%d%d",&n,&m); memset(Head,0,sizeof(Head)); len=0; for(int i=1;i<n;i++){ int a,b,c; scanf("%d%d%d",&a,&b,&c); Ins(a,b,c);Ins(b,a,c); } for(int i=1;i<=m;i++){ int op,x,y,z; scanf("%d",&op); if(op==1){ scanf("%d%d%d",&x,&y,&z); for(int i=Head[x];i;i=e[i].nxt) if(e[i].to==y)e[i].val=z; for(int i=Head[y];i;i=e[i].nxt) if(e[i].to==x)e[i].val=z; } else { int cnt=0; scanf("%d",&x); for(int i=Head[x];i;i=e[i].nxt)cnt+=e[i].val; if(cnt&1)printf("Girls win!\n"); else printf("Boys win!\n"); } } } }
寫完以後感受就這麼過去的話不是很好,萬一猜錯了就很尷尬,因此想一下證實。
爲了簡化問題,咱們只把鏈的狀況證實了就好。若是鏈接根節點的邊權值爲1,其他邊有兩種狀況,一是全爲1的,二是含0的,分開討論一下。
若是含有0,
由於是女生先任意選點,因此讓女生選擇最後一個點,這樣鏈接根節點的那條邊就會被置爲0,而由於含有0,因此確定還會剩下邊權爲1的,這時因爲男生不得不去變換邊,因此必定會去變換權值爲1的,因爲根節點在男生變換的時候爲0,因此這樣的話只有多是女生讓根節點變爲0,也就是隻有女生會贏。
若是不含0都是1呢?那女生就能夠一次性讓男生沒的變換,仍然是女生贏。
當鏈接根節點的邊權值爲0時就會反過來,證畢。spa