[JZOJ5939]【NOIP2018模擬10.30】阻擊計劃
Description
小R和小Z打算在這個週末一起騎車在G國的城市看風景,G國的城市有n個城市,m條雙向道路,這m條邊中,有n-1條道路已經鋪設完畢,任意兩個城市之間都有一條由鋪設好的道路組成的路徑。
由於G國經常收到周圍強大力場的影響,**G國的每個城市至多是十條道路的端點(**包括鋪設好和未鋪設好的道路)。
小R和小Z制訂了這樣一個Van耍計劃:從一個城市開始,沿著G國的道路騎行,途中不經過之前已經去過的城市,也不經過之前去過的道路,最後回到起點城市。
由於他們騎得是雙人自行車,前排的座位比後排的作為更累,他們決定每次到達一個城市都會換一次位置,為了保證每個人的體力消耗相同,繼續進行他們下面的遊戲,他們需要一條恰好有偶數條道路的路徑。
為了阻止他們,小J決定破壞一些沒有被鋪設好的道路,由於自身能力不足,他找到了你,並將自己一週的研究資料——破壞每條未被鋪設好的道路的花費告訴了你,希望你幫他算出他至少需要花費多少代價才能阻止小R和小Z的計劃。
對於所有資料 n≤1000,m≤5000,每條道路的花費≤10000
Solution
題目大意:給定一棵n個節點m條邊的無向圖,每條邊有一個刪除所需要的花費,這m條邊中有n-1條是不能刪除的,並且它們構成一個生成樹。
求最少的花費刪掉一些非樹邊使得原圖不存在邊數為偶數的環。
我們在這棵生成樹上考慮
假設對於一條非樹邊,它本身+樹邊構成了一個偶環,那顯然它是要直接刪掉的,直接累加。
如果它+樹邊構成了一個奇環,我們考慮它們什麼時候會變成偶環。
我們不妨把這條非樹邊對應成兩個端點在樹上的路徑,可以發現,如果任意兩條這樣的路徑出現了重疊邊(重疊點是可以的),那麼就會出現偶環。
問題轉化為,我們最多能保留多少代價和的鏈,使得這些鏈沒有重疊邊。
考慮將這些鏈都掛在它們的LCA上進行DP
設
對於一個點,列舉每條以它為LCA的鏈,轉移相當於對於這條鏈上的所有點k的 ,S’的除了鏈上的兒子是0,其他都是1
對於i,我們剛剛更新的和可以與所有 ,且T的這條鏈的兩個兒子都為0合併成
此外,還可以直接對於每個兒子直接繼承,並將這個兒子邊設為已覆蓋
這樣對於每條鏈都
合併一次,每個兒子也都
合併一次,複雜度就是
的
Code
#include <cstdio>
#include <cstdlib>
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fod(i,a,b) for(int i=a;i>=b;--i)
#define N 5005
using namespace std;
int n,m,f[1005][2048],fa[N][20],dep[N],a[N][5],fs[N],nt[2*N],dt[2*N],num,m1,ans,s1[N],n1,fn[N],cf[12];
vector<int> dq[N];
int lca(int x,int y)
{
if(dep[x]>dep[y]) swap(x,y);
for(int j=dep[y]-dep[x],c=0;j;c++,j>>=1) if(j&1) y=fa[y][c];
for(int j=19;x!=y;)
{
while(j&&fa[x][j]==fa[y][j]) j--;
x=fa[x][j],y=fa[y][j];
}
return x;
}
int jump(int x,int f)
{
if(x==f) return x;
for(int j=dep[x]-dep[f]-1,c=0;j;c++,j>>=1) if(j&1) x=fa[x][c];
return x;
}
void dfs(int k)
{
dep[k]=dep[fa[k][0]]+1;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=fa[k][0])
{
fa[p][0]=k;
dfs(p);
}
}
}
void link(int x,int y)
{
nt[++m1]=fs[x];
dt[fs[x]=m1]=y;
}
void dp(int k)
{
int c=0;
for(int i=fs[k];i;i=nt[i])
{
int p=dt[i];
if(p!=fa[k][0])
{
dp(p),fn[p]=c++;
fo(j,0,2047) if(!(j&cf[fn[p]]))f[k][j^cf[fn[p]]]=max(f[k][j^cf[fn[p]]],f[k][j]+f[p][2047]);
}
}
int l=dq[k].size();
fo(i,0,l-1)
{
int t=dq[k][i],x=a[t][0],y=a[t][1],s=0,lx=-1,ly=-1;
while(x!=k)
{
if(lx<0) s+=f[x][cf[11]-1];
else s+=f[x][(cf[11]-1)^cf[lx]];
lx=fn[x],x=fa[x][0];
}
while(y!=k)
{
if(ly<0) s+=f[y][cf[11]-1];
else s+=f[y][(cf[11]-1)^cf[ly]];
ly=fn[y],y=fa[y][0];
}
x=a[t][3],y=a[t][4],lx=0;
if(x!=k) lx^=cf[fn[x]];
if(y!=k) lx^=cf[fn[y]];
fo(j,0,2047)
{
if(!(j&lx)) f[k][j^lx]=max(f[k][j^lx],s+a[t][2]+f[k][j]);
}
}
}
int main()
{
cin>>n>>m;
fo(i,1,m)
{
int x,y,z;
scanf("%d%d%d",&x,&y,&z);
if(z==0) link(x,y),link(y,x);
else a[++num][0]=x,a[num][1]=y,a[num][2]=z;
}
dfs(1);
fo(i,0,11) cf[i]=1<<i;
fo(j,1,19)
fo(i,1,n) fa[i][j]=fa[fa[i][j-1]][j-1];
ans=0;
fo(i,1,num)
{
int x=a[i][0],y=a[i][1],p=lca(x,y);
if((dep[x]+dep[y]-2*dep[p]+1)%2==0) ans+=a[i][2];
else dq[p].push_back(i),a[i][3]=jump(x,p),a[i][4]=jump(y,p),ans+=a[i][2];
}
dp(1);
int sv=0;
fo(j,0,2047) sv=max(sv,f[1][j]);
printf("%d\n",ans-sv);
}