給出一棵樹,有m組詢問,每次詢問給出兩個點,規定他們必須選或必須不選。求樹的最小權覆蓋集。
此題有倍增+樹形dp的做法,常數非常優秀,但思路比較難想到。
顯然最小權覆蓋集=總點權和-最大權獨立集
看到最大權獨立集,我們想到板子題[luogup4719][模板]動態dp.
考慮如何處理詢問。由於我們要權值最小,如果必須選某個點,就把它的點權修改為\(-\infty\),如果必須不選,就修改為\(+\infty\).**實現上就把它修改成乙個較大的數即可,如\(10^\).然後用板子求最大權獨立集,再用總和減去。注意當我們把點權修改為\(-\infty\)時,最小權覆蓋集會包含\(-\infty\),這時算出的和並不是真正答案,還要加上\(v_x-(-\infty)\),其中\(v_x\)是被強制選的值。
因為樹剖和lct兩種實現動態dp的方式常數過大,沒有o2的情況下會tle,而眾所周知noip是沒有o2優化的。因此這裡只給出全域性平衡二叉樹寫法的**。另外兩種做法的**可以從[luogup4719][模板]動態dp稍加修改得到。
全域性平衡二叉樹
#include#include#include#define inf 0x3f3f3f3f3f3f3f3f
#define maxx 1e10
#define maxn 200000
using namespace std;
typedef long long ll;
templatevoid qread(t &x)
while(c>='0'&&c<='9')
x=x*sign;
} templatevoid qprint(t x)else if(x==0)else
}int n,m;
struct edge e[maxn*2+5];
int head[maxn+5];
int esz=1;
void add_edge(int u,int v)
struct matrix
friend matrix operator * (matrix p,matrix q)
}} return ans;
} ll* operator (int i)
} mat[maxn+5];
ll val[maxn+5];
ll f[maxn+5][2],g[maxn+5][2];
int sz[maxn+5],lsz[maxn+5],son[maxn+5];
void dfs1(int x,int fa)
int build(int x,int f) else
for(int i=head[x]; i; i=e[i].next)
return rt;
} void update(int x)
push_up(x);
if(f&&is_root(x))
x=fa(x);
} }void ini()
void change(int x,ll v)
ll query()
void debug()
} t;
ll query(int x,int tx,int y,int ty) else
if(ty==1) else
ll maxuni=t.query();
ll ans=sum-maxuni+delta;
if(ans>=maxx) ans=-1;
t.change(x,tmpx);
t.change(y,tmpy);
return ans;
}int main()
for(int i=1; it.ini();
for(int i=1; i<=m; i++)
}
NOIP2018 保衛王國
題目 強制選點我們可以把那個點權搞成 inf 強制不選我們搞成 inf 之後就真的成為動態 dp 的板子題了 由於不想像板子那樣再寫乙個最大獨立集的方程,之後利用最小點覆蓋 總點權 最大獨立集的做法,而直接寫了乙個最小點覆蓋的方程,所以寫出了很多鍋 矩陣裡存放相同意義變數的位置可能真實值不相等,於是...
NOIP2018 保衛王國
給定一棵樹,求它的最小點權覆蓋集,其中允許強制某個點選或不選 ddp用lct維護 明確乙個關係式 最小點權覆蓋集 全集 最大點權獨立集 那麼n 2000的暴力就很簡單了,暴力修改,然後求最大點權獨立集就好了 我在考場上就是這麼寫的 關於正解,我採用的是動態dp 動態dp的題解點這裡 根據上面的式子,...
NOIP2018 保衛王國(動態DP)
求最小權值點覆蓋。m mm次詢問,每次給出兩個點,分別要求每個點必須選或必須不選,輸出每次的最小權值覆蓋或者無解輸出 1 1 1強制選或者不選可以看做修改權值為 pm infin 那麼就是這道板題了。include using namespace std typedef long long ll t...