JZOJ 5939. 【NOIP2018模拟10.30】阻击计划
Description
最近,小J發(fā)現(xiàn)小R和小Z之間的關(guān)系十分密切,心中十分嫉妒,為了拆散他們,小J經(jīng)常擾亂他們一起玩耍的計(jì)劃。
問題描述
小R和小Z打算在這個(gè)周末一起騎車在G國的城市看風(fēng)景,G國的城市有n個(gè)城市,m條雙向道路,這m條邊中,有n-1條道路已經(jīng)鋪設(shè)完畢,任意兩個(gè)城市之間都有一條由鋪設(shè)好的道路組成的路徑。
由于G國經(jīng)常收到周圍強(qiáng)大力場的影響,G國的每個(gè)城市至多是十條道路的端點(diǎn)(包括鋪設(shè)好和未鋪設(shè)好的道路)。
小R和小Z制訂了這樣一個(gè)Van耍計(jì)劃:從一個(gè)城市開始,沿著G國的道路騎行,途中不經(jīng)過之前已經(jīng)去過的城市,也不經(jīng)過之前去過的道路,最后回到起點(diǎn)城市。
由于他們騎得是雙人自行車,前排的座位比后排的作為更累,他們決定每次到達(dá)一個(gè)城市都會(huì)換一次位置,為了保證每個(gè)人的體力消耗相同,繼續(xù)進(jìn)行他們下面的游戲,他們需要一條恰好有偶數(shù)條道路的路徑。
為了阻止他們,小J決定破壞一些沒有被鋪設(shè)好的道路,由于自身能力不足,他找到了你,并將自己一周的研究數(shù)據(jù)——破壞每條未被鋪設(shè)好的道路的花費(fèi)告訴了你,希望你幫他算出他至少需要花費(fèi)多少代價(jià)才能阻止小R和小Z的計(jì)劃。
Input
第一行兩個(gè)正整數(shù)n,m表示G國的城市數(shù)和道路數(shù)
接下來m行,每行三個(gè)整數(shù)A,B,C,表示G國的一條道路,從A出發(fā)到B,破壞它的代價(jià)為C(未經(jīng)鋪設(shè)的道路C值一定不為0),由于小J智商有限,已經(jīng)鋪設(shè)好的道路他不能毀壞,也就失去了偵察的必要,他們的花費(fèi)為0
Output
一行一個(gè)整數(shù)表示小J的最小花費(fèi)
Sample Input
Sample Input1:
5 8
2 1 0
3 2 0
4 3 0
5 4 0
1 3 2
3 5 2
2 4 5
2 5 1
Sample Input2:
9 14
1 2 0
1 3 0
2 3 14
2 6 15
3 4 0
3 5 0
3 6 12
3 7 13
4 6 10
5 6 0
5 7 0
5 8 0
6 9 11
8 9 0
Sample Output
Sample Output1:
5
樣例說明
破壞道路1-3,3-5,2-5
Sample Output2:
48
Data Constraint
對(duì)于5%的數(shù)據(jù),任何一條未經(jīng)鋪設(shè)的道路兩端都有一條直接連著他們的鋪設(shè)好的道路
對(duì)于另外10%的數(shù)據(jù),最多只有10條未被鋪設(shè)的道路
對(duì)于另外15%的數(shù)據(jù),最多只有21條未被鋪設(shè)的道路
對(duì)于上述兩檔部分分,數(shù)據(jù)有梯度
對(duì)于另外30%的數(shù)據(jù),已經(jīng)鋪設(shè)好的道路構(gòu)成一條鏈
對(duì)于所有數(shù)據(jù) n≤1000,m≤5000,每條道路的花費(fèi)≤10000
Solution
-
如果連接的新邊使圖構(gòu)成一個(gè)偶環(huán)的話肯定就不行了,也就是連接兩點(diǎn)的樹上路徑長度不能為奇數(shù)。
-
而且就算加進(jìn)來是一個(gè)奇環(huán),兩個(gè)奇環(huán)相交后也能形成一個(gè)偶環(huán),這也不行。
-
轉(zhuǎn)化一下,也就是說我們需要加最大權(quán)值的邊使原樹變成一顆仙人掌。
-
看到一個(gè)點(diǎn)的度數(shù)不超過 101010 ,我們考慮 DP 。
-
設(shè) f[i][S]f[i][S]f[i][S] 表示以 iii 為根的子樹且不考慮其一些兒子(其集合為 SSS)的最大權(quán)值。
-
為了順暢轉(zhuǎn)移,我們將形成奇環(huán)(即可能行的)的新邊掛在其兩端點(diǎn) x,yx,yx,y 的 Lca 處。
-
我們 dfs 到一個(gè)點(diǎn)時(shí)就先處理完其子樹的 fff ,之后就能將掛在該點(diǎn)上的新邊拿出來更新答案。
-
先賦初值:f[x][i]=∑j?if[j][0]f[x][i]=\sum_{j?i}f[j][0]f[x][i]=j∈/?i∑?f[j][0]
-
對(duì)于一對(duì) x,yx,yx,y(其 Lca 為 zzz) ,轉(zhuǎn)移將會(huì)是:f[x][i]=max{f[x][i∣2x′∣2y′]+sum}f[x][i]=max\{f[x][i\ |\ 2^{x'}\ |\ 2^{y'}]+sum\}f[x][i]=max{f[x][i?∣?2x′?∣?2y′]+sum}
-
這里的 x′,y′x',y'x′,y′ 分別是 x,yx,yx,y 到 zzz 路徑上最接近 zzz 的點(diǎn)(即 zzz 的兩個(gè)兒子節(jié)點(diǎn))。
-
而選了 x,yx,yx,y 后其到 zzz 的路徑上就不能再選新邊了,于是我們統(tǒng)計(jì)一個(gè) sumsumsum 記錄產(chǎn)生的轉(zhuǎn)移值。
-
首先有 sum+=Csum+=Csum+=C (即該路徑的權(quán)值)。
-
接著又有:sum+=f[x][0]+f[y][0]sum+=f[x][0]+f[y][0]sum+=f[x][0]+f[y][0] (x,yx,yx,y 下面都能選)
-
然后 x,yx,yx,y 到 zzz 路徑上側(cè)鏈點(diǎn)的值也要統(tǒng)計(jì)上,大概:sum+=f[fa[p]][fa[p]除p外其他兒子]sum+=f[fa[p]][fa[p]除p外其他兒子]sum+=f[fa[p]][fa[p]除p外其他兒子]
-
統(tǒng)計(jì)時(shí)要特判 x=zx=zx=z 或 y=zy=zy=z 的情況。
-
時(shí)間復(fù)雜度 O(nm+210?n)O(nm+2^{10}*n)O(nm+210?n) 。
-
由于數(shù)據(jù)的一些問題,有某些點(diǎn)的度數(shù)竟達(dá)到了12,故以下程序中開到了 2122^{12}212 。
Code
#include<cstdio> #include<algorithm> #include<cmath> #include<vector> #include<cctype> using namespace std; const int N=1005,M=1<<12; struct data {int x,y,z; }a[N<<2]; int tot,num,ans; int first[N],nex[N<<1],en[N<<1]; int dep[N],fa[N][10],p[13]; int f[N][M],val[N],bel[13]; vector<int>ss[N]; inline int read() {int X=0,w=0; char ch=0;while(!isdigit(ch)) w|=ch=='-',ch=getchar();while(isdigit(ch)) X=(X<<3)+(X<<1)+(ch^48),ch=getchar();return w?-X:X; } inline void insert(int x,int y) {nex[++tot]=first[x];first[x]=tot;en[tot]=y; } inline int max(int x,int y) {return x>y?x:y; } void dfs(int x) {dep[x]=dep[fa[x][0]]+1;for(int i=first[x];i;i=nex[i])if(en[i]^fa[x][0]){fa[en[i]][0]=x;dfs(en[i]);} } inline int lca(int x,int y) {if(dep[x]<dep[y]) swap(x,y);for(int i=log2(dep[x]);i>=0;i--)if(dep[fa[x][i]]>=dep[y]) x=fa[x][i];if(x==y) return x;for(int i=log2(dep[x]);i>=0;i--)if(fa[x][i]^fa[y][i]) x=fa[x][i],y=fa[y][i];return fa[x][0]; } void dfs1(int x) {for(int i=first[x];i;i=nex[i])if(en[i]^fa[x][0]) dfs1(en[i]);tot=0;for(int i=first[x];i;i=nex[i])if(en[i]^fa[x][0]){bel[tot]=en[i];val[en[i]]=p[tot++];}for(int i=0;i<p[tot];i++){int sum=0;for(int j=0;j<tot;j++)if(!(i&p[j])) sum+=f[bel[j]][0];f[x][i]=sum;}for(int i=0;i<(int)ss[x].size();i++){int id=ss[x][i],px=0,py=0;int xx=a[id].x,yy=a[id].y,sum=a[id].z;if(xx^x){sum+=f[xx][0];for(px=xx;fa[px][0]^x;px=fa[px][0]) sum+=f[fa[px][0]][val[px]];}if(yy^x){sum+=f[yy][0];for(py=yy;fa[py][0]^x;py=fa[py][0]) sum+=f[fa[py][0]][val[py]];}for(int j=0;j<p[tot];j++)if(!(j&val[px]) && !(j&val[py]))f[x][j]=max(f[x][j],f[x][j|val[px]|val[py]]+sum);} } int main() {freopen("zujijihua.in","r",stdin);freopen("zujijihua.out","w",stdout);int n=read(),m=read();for(int i=1;i<=m;i++){int x=read(),y=read(),z=read();if(!z){insert(x,y);insert(y,x);}else{a[++num]=(data){x,y,z};ans+=z;}}dfs(1);for(int i=p[0]=1;i<13;i++) p[i]=p[i-1]<<1;for(int j=1;j<10;j++)for(int i=1;i<=n;i++)fa[i][j]=fa[fa[i][j-1]][j-1];for(int i=1;i<=num;i++){int x=a[i].x,y=a[i].y,z=lca(x,y);if((dep[x]+dep[y]-dep[z]*2)%2==0) ss[z].push_back(i);}dfs1(1);printf("%d",ans-f[1][0]);return 0; }總結(jié)
以上是生活随笔為你收集整理的JZOJ 5939. 【NOIP2018模拟10.30】阻击计划的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: JZOJ 5938. 【NOIP2018
- 下一篇: JZOJ 5941. 【NOIP2018