[NOIP 2018 提高组] 保卫王国
[NOIP 2018 提高组] 保卫王国
比较不错的动态 dp 综合题。
题意
给定一棵 \(n\) 个节点的带点权的树,第 \(i\) 个点的点权是 \(p_i\)。
现在有 \(m\) 个询问,每次询问给定两个点 \(a\) 和 \(b\) 并指定这两个点选或不选,求树的最小权点覆盖。
\(1 \leq n,m \leq 10^5\),\(1 \leq p_i \leq 10^5\)。
思路
先判断无解情况。
题目有强制选点,可以通过把点权设为正无穷或负无穷实现。
接下来考虑如何求出最小权点覆盖。
最小权点覆盖加最大权独立集等于全集,所以只需要求出最大权独立集即可。
注意细节,可能会造成精神污染。
代码
#include<iostream>
#include<cstdio>
#include<vector>
#include<unordered_map>
using namespace std;
const long long INF=0x3f3f3f3f3f3f3f3f,inf_max=0x3f3f3f3f3f3f,inf_min=-0x3f3f3f3f3f3f;
int tot,son[100010],pa[100010];
int dfn[100010],top[100010],rev[100010],bottom[100010],child[100010];
long long num[100010],dp_f[100010][2],dp_g[100010][2];
vector<int> G[100010],T[100010];
void dfs1(int u,int fa){
child[u]=1;
for(int i=0;i<G[u].size();i++){
int v=G[u][i];
if(v!=fa){
T[u].push_back(v);
pa[v]=u;
dfs1(v,u);
child[u]+=child[v];
if(child[v]>=child[son[u]]){
son[u]=v;
}
}
}
}
void dfs2(int u,int fa){
rev[++tot]=u;
dfn[u]=tot;
top[u]=fa;
bottom[fa]=u;
if(son[u]){
dfs2(son[u],fa);
}
for(int i=0;i<T[u].size();i++){
int v=T[u][i];
if(v!=son[u]){
dfs2(v,v);
}
}
}
void dfs3(int u){
dp_f[u][1]=dp_g[u][1]=num[u];
for(int i=0;i<T[u].size();i++){
int v=T[u][i];
dfs3(v);
dp_f[u][0]+=max(dp_f[v][0],dp_f[v][1]);
dp_f[u][1]+=dp_f[v][0];
if(v!=son[u]){
dp_g[u][0]+=max(dp_f[v][0],dp_f[v][1]);
dp_g[u][1]+=dp_f[v][0];
}
}
}
struct Matrix{
long long matrix[2][2];
};
const Matrix operator *(const Matrix &x,const Matrix &y){
Matrix z;
for(int i=0;i<2;i++){
for(int j=0;j<2;j++){
z.matrix[i][j]=max(x.matrix[i][0]+y.matrix[0][j],x.matrix[i][1]+y.matrix[1][j]);
}
}
return z;
}
struct Node{
int l,r;
Matrix g;
}a[400010];
void pushup(int id){
a[id].g=a[id*2].g*a[id*2+1].g;
}
void build(int id,int l,int r){
a[id].l=l;
a[id].r=r;
if(a[id].l==a[id].r){
a[id].g.matrix[0][0]=a[id].g.matrix[0][1]=dp_g[rev[l]][0];
a[id].g.matrix[1][0]=dp_g[rev[l]][1];
a[id].g.matrix[1][1]=-INF;
}
else{
int mid=(l+r)>>1;
build(id*2,l,mid);
build(id*2+1,mid+1,r);
pushup(id);
}
}
Matrix query(int id,int l,int r){
if(l<=a[id].l && a[id].r<=r){
return a[id].g;
}
bool flag=false;
Matrix ans;
if(l<=a[id*2].r){
flag=true;
ans=query(id*2,l,r);
}
if(a[id*2+1].l<=r){
if(flag==false){
ans=query(id*2+1,l,r);
}
else{
ans=ans*query(id*2+1,l,r);
}
}
return ans;
}
void modify(int id,int pos,Matrix dif){
if(a[id].l==a[id].r){
a[id].g=dif;
return ;
}
if(pos<=a[id*2].r){
modify(id*2,pos,dif);
}
else{
modify(id*2+1,pos,dif);
}
pushup(id);
}
struct Query{
long long dp0,dp1;
};
Query query_f(int u){
int id_u=dfn[u],id_bottom=dfn[bottom[u]];
Matrix tmp=query(1,id_bottom,id_bottom),tmp2=query(1,id_u,id_bottom-1);
Query tmp3=(Query){tmp.matrix[0][0],tmp.matrix[1][0]};
if(id_bottom==id_u) return tmp3;
Query ans=(Query){max(tmp2.matrix[0][0]+tmp3.dp0,tmp2.matrix[0][1]+tmp3.dp1),max(tmp2.matrix[1][0]+tmp3.dp0,tmp2.matrix[1][1]+tmp3.dp1)};
return ans;
}
unordered_map<int,unordered_map<int,bool> > road;
int main(){
int n,m;
scanf("%d %d",&n,&m);
string subtask;
cin>>subtask;
long long sum=0;
for(int i=1;i<=n;i++){
scanf("%lld",&num[i]);
sum+=num[i];
}
for(int i=1;i<n;i++){
int u,v;
scanf("%d %d",&u,&v);
G[u].push_back(v);
G[v].push_back(u);
road[u][v]=road[v][u]=true;
}
dfs1(1,-1);
dfs2(1,1);
dfs3(1);
for(int i=1;i<=n;i++){
bottom[i]=bottom[top[i]];
}
build(1,1,n);
while(m--){
int u1,d1,u2,d2;
scanf("%d %d %d %d",&u1,&d1,&u2,&d2);
if(road[u1][u2] && d1==0 && d2==0){
printf("-1\n");
continue;
}
long long dif=0;
long long tmp_u1=u1,lst_num_u1=num[u1],dif_num_u1;
if(d1==0){
dif_num_u1=inf_max;
dif+=num[u1]-inf_max;
}
else dif_num_u1=inf_min;
Query lst=query_f(top[u1]);
Matrix tmp=query(1,dfn[u1],dfn[u1]);
tmp.matrix[1][0]+=dif_num_u1-num[u1];
num[u1]=dif_num_u1;
modify(1,dfn[u1],tmp);
while(top[u1]!=1){
int pre=top[u1];
Query f=query_f(pre);
int fa=pa[pre];
tmp=query(1,dfn[fa],dfn[fa]);
tmp.matrix[0][0]+=max(f.dp0,f.dp1)-max(lst.dp0,lst.dp1);
tmp.matrix[0][1]+=max(f.dp0,f.dp1)-max(lst.dp0,lst.dp1);
tmp.matrix[1][0]+=f.dp0-lst.dp0;
lst=query_f(top[fa]);
modify(1,dfn[fa],tmp);
u1=fa;
}
long long tmp_u2=u2,lst_num_u2=num[u2],dif_num_u2;
if(d2==0){
dif_num_u2=inf_max;
dif+=num[u2]-inf_max;
}
else dif_num_u2=inf_min;
lst=query_f(top[u2]);
tmp=query(1,dfn[u2],dfn[u2]);
tmp.matrix[1][0]+=dif_num_u2-num[u2];
num[u2]=dif_num_u2;
modify(1,dfn[u2],tmp);
while(top[u2]!=1){
int pre=top[u2];
Query f=query_f(pre);
int fa=pa[pre];
tmp=query(1,dfn[fa],dfn[fa]);
tmp.matrix[0][0]+=max(f.dp0,f.dp1)-max(lst.dp0,lst.dp1);
tmp.matrix[0][1]+=max(f.dp0,f.dp1)-max(lst.dp0,lst.dp1);
tmp.matrix[1][0]+=f.dp0-lst.dp0;
lst=query_f(top[fa]);
modify(1,dfn[fa],tmp);
u2=fa;
}
lst=query_f(1);
printf("%lld\n",sum-max(lst.dp0,lst.dp1)-dif);
u1=tmp_u1;
lst=query_f(top[u1]);
tmp=query(1,dfn[u1],dfn[u1]);
tmp.matrix[1][0]+=lst_num_u1-num[u1];
num[u1]=lst_num_u1;
modify(1,dfn[u1],tmp);
while(top[u1]!=1){
int pre=top[u1];
Query f=query_f(pre);
int fa=pa[pre];
tmp=query(1,dfn[fa],dfn[fa]);
tmp.matrix[0][0]+=max(f.dp0,f.dp1)-max(lst.dp0,lst.dp1);
tmp.matrix[0][1]+=max(f.dp0,f.dp1)-max(lst.dp0,lst.dp1);
tmp.matrix[1][0]+=f.dp0-lst.dp0;
lst=query_f(top[fa]);
modify(1,dfn[fa],tmp);
u1=fa;
}
u2=tmp_u2;
lst=query_f(top[u2]);
tmp=query(1,dfn[u2],dfn[u2]);
tmp.matrix[1][0]+=lst_num_u2-num[u2];
num[u2]=lst_num_u2;
modify(1,dfn[u2],tmp);
while(top[u2]!=1){
int pre=top[u2];
Query f=query_f(pre);
int fa=pa[pre];
tmp=query(1,dfn[fa],dfn[fa]);
tmp.matrix[0][0]+=max(f.dp0,f.dp1)-max(lst.dp0,lst.dp1);
tmp.matrix[0][1]+=max(f.dp0,f.dp1)-max(lst.dp0,lst.dp1);
tmp.matrix[1][0]+=f.dp0-lst.dp0;
lst=query_f(top[fa]);
modify(1,dfn[fa],tmp);
u2=fa;
}
}
return 0;
}

浙公网安备 33010602011771号