日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

UOJ#84-[UR #7]水题走四方【dp】

發(fā)布時(shí)間:2023/12/3 编程问答 51 豆豆
生活随笔 收集整理的這篇文章主要介紹了 UOJ#84-[UR #7]水题走四方【dp】 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

正題

題目鏈接:https://uoj.ac/problem/84


題目大意

nnn個(gè)點(diǎn)的一棵樹(shù),111為根,兩個(gè)人從根節(jié)點(diǎn)往下走(只能從深度小的點(diǎn)走到深度大的點(diǎn))。

兩個(gè)人每一秒都可以一條邊(也可以不移動(dòng)),或者不消耗時(shí)間將一個(gè)人傳送到另一個(gè)人那里。

求遍歷整棵樹(shù)需要的最少時(shí)間。

1≤n≤5×1061\leq n\leq 5\times 10^61n5×106


解題思路

什么神仙題。

首先考慮到肯定存在一種方案使得一個(gè)人不需要使用傳送,因?yàn)轱@然兩個(gè)人都需要使用傳送的方案可以通過(guò)交換兩個(gè)人的某些路徑得到有一個(gè)人不需要傳送的方案。

那么說(shuō)明其中一個(gè)人的路徑肯定是一條鏈,我們將這個(gè)人稱(chēng)之為本體,另一個(gè)人稱(chēng)為分身。

然后一個(gè)粗暴的想法是dpdpdp出一條路徑,然后本體每走到一個(gè)點(diǎn)就等分身遍歷完除了鏈上的其他子樹(shù)再往下一個(gè)節(jié)點(diǎn)走。設(shè)fif_ifi?表示走到節(jié)點(diǎn)iii的答案。

但是這樣顯然是會(huì)出問(wèn)題的,對(duì)于節(jié)點(diǎn)xxx不一定是從它的父親處轉(zhuǎn)移的,因?yàn)閮蓚€(gè)人可以同時(shí)移動(dòng),當(dāng)分身最后一次傳送后本體可以和分身一起移動(dòng)然后本體在下一個(gè)路口等分身傳送。

讓本體等分身是一種可能更賺的方案如圖(邊長(zhǎng)代指了中間省略的點(diǎn)數(shù)量級(jí)別)

顯然當(dāng)本體等待分身遍歷完1~51\sim 515之后讓本體和分身分別走向444333是更優(yōu)的做法。

可以相當(dāng)于在鏈上選擇一些關(guān)鍵點(diǎn),本體只有在關(guān)鍵點(diǎn)時(shí)才等待,并且分身最后遍歷最深的葉子時(shí)本體同時(shí)出發(fā)。而關(guān)鍵點(diǎn)不連續(xù)的條件只有本體等分身的時(shí)才會(huì)出現(xiàn),也就是分身最后遍歷的葉子深度比下一個(gè)關(guān)鍵點(diǎn)的深度要大。

而且顯然地如果出現(xiàn)了這種情況那么選擇另一個(gè)深度更小的祖先作為上一個(gè)關(guān)鍵點(diǎn)不可能更優(yōu)(因?yàn)闀?huì)走同一段)

所以我們只需要對(duì)于每個(gè)節(jié)點(diǎn)xxx找到第一個(gè)祖先yyy滿足yyy的子樹(shù)除去xxx的子樹(shù)后存在一個(gè)深度比xxx大的節(jié)點(diǎn)記為sfxsf_xsfx?。

那么每個(gè)節(jié)點(diǎn)只需從sfxsf_xsfx?轉(zhuǎn)移即可,如果找不到sfsfsf的節(jié)點(diǎn)顯然對(duì)于這樣的節(jié)點(diǎn)它的父節(jié)點(diǎn)只會(huì)有一個(gè)子節(jié)點(diǎn),那么令fx=ffax+1f_x=f_{fa_x}+1fx?=ffax??+1即可。

問(wèn)題是如何快速的求出每個(gè)sfxsf_xsfx?,注意到對(duì)于一個(gè)處理好的子樹(shù)xxx只有可能有一段連續(xù)的鏈沒(méi)有sfxsf_xsfx?(如圖紅色箭頭所指部分)

所以我們只需要從小往上處理維護(hù)每個(gè)處理好的子樹(shù)的sfsfsf000的鏈。

然后兩棵子樹(shù)的時(shí)候我們直接暴力合并這些部分即可,因?yàn)楹喜⑼曛罂隙ㄖ粫?huì)留下長(zhǎng)的那條鏈多出來(lái)的部分。

時(shí)間復(fù)雜度:O(n)O(n)O(n)


code

#include<cstdio> #include<cstring> #include<algorithm> #define ll long long using namespace std; const ll N=5e6+10; ll n,ans,deg[N],dep[N],fa[N],sf[N]; ll siz[N],sum[N],mx[N],nxt[N],f[N]; char s[N<<1]; void addl(ll x,ll y){deg[x]++;fa[y]=x;dep[y]=dep[x]+1;return; } signed main() {scanf("%lld",&n);if(n==1)return puts("0")&0;scanf("%s",s+1);for(ll i=1,now=0,cnt=0;i<=2*n;i++){if(s[i]=='(')++cnt,addl(now,cnt),now=cnt;else now=fa[now];}for(ll i=n;i>1;i--){if(!deg[i])siz[i]=1,sum[i]=mx[i]=dep[i];ll x,y;for(x=i;x&&dep[x]<=mx[fa[i]];x=nxt[x])sf[x]=fa[i];for(y=nxt[fa[i]];y&&dep[y]<=mx[i];y=nxt[y])sf[y]=fa[i];nxt[fa[i]]=x+y;sum[fa[i]]+=sum[i];siz[fa[i]]+=siz[i];mx[fa[i]]=max(mx[fa[i]],mx[i]);}f[1]=0;ans=n*n+100;for(ll i=2;i<=n;i++){f[i]=n*n+100;ll x=sf[i];if(x)f[i]=f[x]+sum[x]-sum[i]-dep[x]*(siz[x]-siz[i]);if(deg[fa[i]]==1)f[i]=min(f[i],f[fa[i]]+1);if(!deg[i])ans=min(ans,f[i]);}printf("%lld\n",ans);return 0; }

總結(jié)

以上是生活随笔為你收集整理的UOJ#84-[UR #7]水题走四方【dp】的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。