P7443-加边【博弈论】
正題
題目鏈接:https://www.luogu.com.cn/problem/P7443?contestId=41429
題目大意
nnn個點的一棵有根樹,兩個人從一號點開始進行有向圖博弈。
告訴你Alice是先手還是后手,然后你可以選擇加一條鏈接(u,v)(u,v)(u,v)的有向邊,權(quán)值為A×au+B×avA\times a_u+B\times a_vA×au?+B×av?。求最小權(quán)值使得第一個人獲勝。(如果死循環(huán)則無法獲勝)
1≤T≤2×103,2≤n≤2×105,∑n≤5×106,1≤ai,A,B≤1091\leq T\leq 2\times 10^3,2\leq n\leq 2\times 10^5,\sum n\leq 5\times 10^6,1\leq a_i,A,B\leq 10^91≤T≤2×103,2≤n≤2×105,∑n≤5×106,1≤ai?,A,B≤109
解題思路
先考慮沒有加邊情況的勝負。定義111為先手必敗狀態(tài),那么所有葉子都是111。然后每個節(jié)點是所有子節(jié)點的或值再異或111。
那么如果已經(jīng)必勝就是000了,否則我們需要改變一號節(jié)點的狀態(tài)。
先考慮加一條返祖邊的影響,首先這條邊肯定是加在Alice行動的節(jié)點上,否則Bob可以選擇不走。
而且vvv肯定得是先手必敗的局面,否則沒有意義。然后如果vvv是先手必敗的話,那么Bob顯然還是可以往之前的路徑走,如果走到uuu節(jié)點時是Alice移動那么狀態(tài)不會改變,否則Bob可以繼續(xù)走返祖邊造成死循環(huán)。所以返祖邊不能影響狀態(tài)。
然后考慮翻轉(zhuǎn)一個點的狀態(tài)需要做什么。
如果這個點是先手必敗,那么我們只需要找到另一個先手必敗的節(jié)點連接過去或者翻轉(zhuǎn)子節(jié)點的狀態(tài)就可以翻轉(zhuǎn)該節(jié)點的狀態(tài)。
如果這個點是先手必勝,那么如果子節(jié)點中有兩個或以上的先手必敗那么該節(jié)點無法翻轉(zhuǎn),否則翻轉(zhuǎn)那個先手必敗的節(jié)點即可。
那么現(xiàn)在我們需要解決尋找除了該節(jié)點到根的路徑上的點中權(quán)值最小的先手必敗節(jié)點權(quán)值。
用優(yōu)先隊列的話會TLETLETLE,所以我們考慮其他方法,我們對于每個節(jié)點記錄一下子樹中最大的先手必敗節(jié)點權(quán)值,然后每次向下遞歸的時候就取所有除了遞歸子樹以外的子節(jié)點子樹丟進最小值就好了。
這個記錄一個次大值和最大值就可以實現(xiàn)。
時間復雜度O(∑n)O(\sum n)O(∑n)
code
#include<cstdio> #include<cstring> #include<algorithm> #include<cctype> #include<queue> #define ll long long using namespace std; const ll N=2e5+10; struct node{ll to,next; }a[N]; ll T,n,m,t,A,B,tot,w[N],fa[N],z[N]; ll ls[N],f[N],s[N],ans; ll read(){ll x=0,f=1;char c=getchar();while(!isdigit(c)){if(c=='-')f=-f;c=getchar();}while(isdigit(c)){x=(x<<1)+(x<<3)+c-'0';c=getchar();}return x*f; } void addl(ll x,ll y){a[++tot].to=y;a[tot].next=ls[x];ls[x]=tot;return; } void dfs(ll x){f[x]=s[x]=0;z[x]=1e9+7;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;dfs(y);f[x]|=f[y];s[x]+=f[y];z[x]=min(z[x],z[y]); }f[x]^=1;if(f[x])z[x]=min(z[x],w[x]);return; } void dp(ll x,ll mins){ll c=mins,zc=mins;for(ll i=ls[x];i;i=a[i].next){ll y=a[i].to;if(z[y]<c)zc=c,c=z[y];else if(z[y]<zc)zc=z[y];}if(f[x]){for(ll i=ls[x];i;i=a[i].next)dp(a[i].to,(z[a[i].to]==c)?zc:c);if(c!=1e9+7)ans=min(ans,w[x]*A+c*B);}else if(s[x]==1){for(ll i=ls[x];i;i=a[i].next)if(f[a[i].to])dp(a[i].to,(z[a[i].to]==c)?zc:c); } } signed main() {T=read();while(T--){n=read();t=read();A=read();B=read();for(ll i=1;i<=n;i++)ls[i]=0;tot=0;for(ll i=2;i<=n;i++)fa[i]=read(),addl(fa[i],i);for(ll i=1;i<=n;i++)w[i]=read();dfs(1);if(f[1]^t^1){puts("0");continue;}else{ans=3e18;dp(1,1e9+7);if(ans==3e18) puts("-1");else printf("%lld\n",ans);}} }總結(jié)
以上是生活随笔為你收集整理的P7443-加边【博弈论】的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 监控系统如何安装台式电脑如何安装监控
- 下一篇: ARC115E-LEQ and NEQ【