jzoj5939 【NOIP2018模擬10.30】阻擊計劃 (樹上小度數狀壓)
阿新 • • 發佈:2018-12-02
對於所有資料 n≤1000,m≤5000,每條道路的花費≤10000
分析
假如一開始就是偶環必然要刪掉。
假如是奇環,相交之後會形成一個偶環,只要邊不相交就行。
考慮到兒子數很少,設狀態
表示i的兒子邊被覆蓋狀態為S。然後列舉lca為當前點的非樹邊,強行計算貢獻即可。
#include <cstdio>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <vector>
using namespace std;
const int N = 5050;
int n,m,ans;
int final[N],nex[N],to[N],tot;
int f[ N][N],g[N],fmx[N],cnt[N];
void link(int x,int y) {
to[++tot] = y,nex[tot] = final[x],final[x] = tot;
}
int e[N][3],ec,rk[N],fa[N],dep[N];
struct edge{
int x,y,v;
}; vector<edge> up[N];
void dfs(int x) {
int r=0; dep[x]=dep[fa[x]]+1;
for (int i = final[x]; i; i = nex[i]) {
int y = to[i] ;
if (y != fa[x]) {
rk[y] = r++;
fa[y] = x;
dfs(y);
}
}
cnt[x] = r;
}
int lca(int x,int y) {
if (dep[x]<dep[y]) swap(x,y);
while (dep[x]>dep[y]) x=fa[x];
if (x==y) return x;
while (x!=y) x=fa[x],y=fa[y];
return x;
}
int getsum(int u,int tu,int &near) {
int ret = fmx[u];
for (; u != tu; u = fa[u]) {
ret += g[u];
if (fa[u] == tu) near |= 1<<rk[u];
}
return ret;
}
edge a;
int count(int x) {
int ret = 0; while (x) x-=x&-x,ret++;
return ret;
}
void solve(int x) {
for (int i = final[x]; i; i=nex[i]) {
int y = to[i]; if (y != fa[x]) {
solve(y);
}
}
while (up[x].size()) {
a = up[x].back(); up[x].pop_back();
int s = 0;
int v = getsum(a.x,x,s);
v += getsum(a.y,x,s) + a.v;
for (int i = 0; i < (1<<cnt[x]); i++) if ((i & s)==0) {
f[x][i | s] = max(f[x][i | s], f[x][i] + v);
}
}
for (int i = 0; i < (1<<cnt[x]); i++) {
for (int j = final[x]; j; j=nex[j]) {
int y = to[j]; if (y != fa[x]) {
if ((i & (1<<rk[y]))==0) {
f[x][i] += fmx[y];
}
}
}
for (int j = final[x]; j; j=nex[j]) {
int y = to[j]; if (y != fa[x]) {
if ((i & (1<<rk[y]))==0) {
g[y] = max(g[y], f[x][i] - fmx[y]);
}
}
}
fmx[x]=max(fmx[x],f[x][i]);
}
}
int he;
int main() {
freopen("zujijihua.in","r",stdin);
freopen("zujijihua.out","w",stdout);
cin>>n>>m;
for (int i = 1; i <= m; i++) {
int u,v,c;scanf("%d %d %d",&u,&v,&c);
if (c==0)
link(u,v),link(v,u);
else {
e[++ec][0] = u,e[ec][1] = v,e[ec][2] = c;
}
ans+=c;
}
dfs(1);
for (int i = 1; i <= ec; i++) {
int l = lca(e[i][0],e[i][1]);
he += e[i][2];
if ((dep[e[i][0]] + dep[e[i][1]] - dep[l] * 2 + 1) & 1) {
up[l].push_back((edge){e[i][0],e[i][1],e[i][2]});
}
}
solve(1);
cout<<he-fmx[1]<<endl;
}