1. 程式人生 > >jzoj5939 【NOIP2018模擬10.30】阻擊計劃 (樹上小度數狀壓)

jzoj5939 【NOIP2018模擬10.30】阻擊計劃 (樹上小度數狀壓)

在這裡插入圖片描述對於所有資料 n≤1000,m≤5000,每條道路的花費≤10000

分析

假如一開始就是偶環必然要刪掉。
假如是奇環,相交之後會形成一個偶環,只要邊不相交就行。
考慮到兒子數很少,設狀態 f i , S

f_{i,S} 表示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; }