做法(倍增)

最好写的一种

以下0为不选,1为选

\(f_{i,0/1}\)为\(i\)子树的最小值,\(g_{i,0/1}\)为除i子树外的最小值

\(fh_{i,j,0/1,0/1}\)为确定\(i\)与\(i\)的\(2^j\)级祖先的状态,\(i\)的\(2^j\)祖先不包括i子树的最小值

这个转移挺好想的,故不赘述

  • 查询

    考虑边倍增爬上去,边处理即可
#include<bits/stdc++.h>
typedef long long LL;
const LL maxn=1e6+9,inf=0x3f3f3f3f3f3f3f3f;
inline LL Read(){
LL x(0),f(1); char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<3)+(x<<1)+c-'0'; c=getchar();
}return x*f;
}
struct node{
LL to,nxt;
}dis[maxn<<1];
LL n,q,num;
LL head[maxn],f[maxn][2],inc[maxn][21],g[maxn][2],fh[maxn][21][2][2],dep[maxn],p[maxn];
char s[3];
inline void Add(LL u,LL v){
dis[++num]=(node){v,head[u]}; head[u]=num;
}
void Dfs1(LL u,LL fa){
inc[u][0]=fa; dep[u]=dep[fa]+1; f[u][1]=p[u];
for(LL i=1;i<=20;++i) inc[u][i]=inc[inc[u][i-1]][i-1];
for(LL i=head[u];i;i=dis[i].nxt){
LL v(dis[i].to); if(v==fa) continue;
Dfs1(v,u);
f[u][0]+=f[v][1]; f[u][1]+=std::min(f[v][0],f[v][1]);
}
}
void Dfs2(LL u,LL fa){
fh[u][0][0][1]=fh[u][0][1][1]=f[fa][1]-std::min(f[u][0],f[u][1]);
fh[u][0][0][0]=inf; fh[u][0][1][0]=f[fa][0]-f[u][1];
for(LL i=1;i<=20;++i)
for(LL x=0;x<=1;++x)
for(LL y=0;y<=1;++y){
fh[u][i][x][y]=inf;
for(LL xx=0;xx<=1;++xx)
fh[u][i][x][y]=std::min(fh[u][i][x][y],fh[inc[u][i-1]][i-1][xx][y]+fh[u][i-1][x][xx]);
}
for(LL i=head[u];i;i=dis[i].nxt){
LL v(dis[i].to); if(v==fa) continue;
g[v][0]=g[u][1]+f[u][1]-std::min(f[v][0],f[v][1]);
g[v][1]=std::min(g[u][0]+f[u][0]-f[v][1],g[v][0]);
Dfs2(v,u);
}
}
inline LL Solve(LL a,LL x,LL b,LL y){
if(dep[a]<dep[b]) std::swap(a,b),std::swap(x,y);
LL aa[2]={inf,inf},ab[2]={inf,inf};
LL ta[2]={inf,inf},tb[2]={inf,inf};
aa[x]=f[a][x]; ab[y]=f[b][y];
for(LL i=20;i>=0;--i){
if(dep[inc[a][i]]>=dep[b]){
for(LL ii=0;ii<=1;++ii){
ta[ii]=inf;
for(LL jj=0;jj<=1;++jj)
ta[ii]=std::min(ta[ii],aa[jj]+fh[a][i][jj][ii]);
}
a=inc[a][i]; aa[1]=ta[1],aa[0]=ta[0];
}
}
if(a==b) return aa[y]+g[a][y];
for(LL i=20;i>=0;--i){
if(inc[a][i]!=inc[b][i]){
for(LL ii=0;ii<=1;++ii){
ta[ii]=tb[ii]=inf;
for(LL jj=0;jj<=1;++jj){
ta[ii]=std::min(ta[ii],aa[jj]+fh[a][i][jj][ii]);
tb[ii]=std::min(tb[ii],ab[jj]+fh[b][i][jj][ii]);
}
}
a=inc[a][i], b=inc[b][i]; aa[1]=ta[1],aa[0]=ta[0]; ab[1]=tb[1],ab[0]=tb[0];
}
}
LL fa=inc[a][0];
LL ans0(aa[1]+ab[1]+(g[fa][0]+f[fa][0]-f[a][1]-f[b][1]));
LL ans1(g[fa][1]+f[fa][1]-std::min(f[a][1],f[a][0])-std::min(f[b][1],f[b][0])+std::min(aa[1],aa[0])+std::min(ab[1],ab[0]));
return std::min(ans0,ans1);
}
int main(){
// freopen("testdata.in","r",stdin);
n=Read(); q=Read(); scanf(" %s",s+1);
for(LL i=1;i<=n;++i) p[i]=Read();
for(LL i=1;i<n;++i){
LL u(Read()),v(Read()); Add(u,v); Add(v,u);
}
Dfs1(1,0); Dfs2(1,0);
while(q--){
LL a(Read()),x(Read()),b(Read()),y(Read());
LL ret(Solve(a,x,b,y));
if(ret>=inf) puts("-1");
else printf("%lld\n",ret);
}
return 0;
}

整体

思维较大,代码细节有点多

f与g与方法一同理得出

考虑类似tarjan离线的处理方式,用并查集,并查集按秩压缩

\(fa_x\)为x暂时在并查集里的父亲,\(h_{x,0/1,0/1}\)表示确定x父亲与x的状态,x父亲这棵子树的最小值,状态转移压缩时处理

当我们得出(x,y)的祖先时,把查询再丢到祖先u去

  • 查询

    对于u存在于(x,y)的情况单独讨论,因为这样u的状态唯一

    否则枚举u状态,\(min(g[u][0]+h[a][0][x]+h[b][0][y]-f[u][0],g[u][1]+h[a][1][x]+h[b][1][y]-f[u][1])\)
#include<bits/stdc++.h>
typedef long long LL;
const LL maxn=1e6+9,inf=0x3f3f3f3f3f3f3f3f;
inline LL Read(){
LL x(0),f(1); char c=getchar();
while(c<'0' || c>'9'){
if(c=='-') f=-1; c=getchar();
}
while(c>='0' && c<='9'){
x=(x<<3)+(x<<1)+c-'0'; c=getchar();
}return x*f;
}
struct node{
LL to,nxt;
}dis[maxn<<1];
struct qy{
LL a,x,b,y,id;
};
LL n,q,num;
LL head[maxn],f[maxn][2],g[maxn][2],h[maxn][2][2],dep[maxn],p[maxn],fa[maxn],nx[2][2],ans[maxn];
std::vector<qy> Qy[maxn],Ans[maxn];
char s[3];
inline void Add(LL u,LL v){
dis[++num]=(node){v,head[u]}; head[u]=num;
}
void Dfs1(LL u,LL ff){
f[u][1]=p[u];
for(LL i=head[u];i;i=dis[i].nxt){
LL v(dis[i].to); if(v==ff) continue;
Dfs1(v,u);
f[u][0]+=f[v][1]; f[u][1]+=std::min(f[v][0],f[v][1]);
}
}
void Dfs2(LL u,LL ff){
for(LL i=head[u];i;i=dis[i].nxt){
LL v(dis[i].to); if(v==ff) continue;
g[v][0]=g[u][1]+f[u][1]-std::min(f[v][0],f[v][1]);
g[v][1]=std::min(g[u][0]+f[u][0]-f[v][1],g[v][0]);
Dfs2(v,u);
}
}
inline void Union(LL x,LL y){
fa[x]=y; LL tmp(f[y][1]-std::min(f[x][0],f[x][1]));
h[x][0][0]=inf; h[x][0][1]=f[y][0]; h[x][1][1]=tmp+f[x][1]; h[x][1][0]=tmp+f[x][0];
}
void Find(LL x){
if(fa[x]==fa[fa[x]]) return;
Find(fa[x]);
LL up(fa[x]);
for(LL i=0;i<=1;++i)
for(LL j=0;j<=1;++j){
nx[i][j]=h[x][i][j]; h[x][i][j]=inf;
}
for(LL i=0;i<=1;++i)
for(LL j=0;j<=1;++j)
for(LL k=0;k<=1;++k)
h[x][i][j]=std::min(h[x][i][j],nx[k][j]+h[up][i][k]-f[up][k]);
fa[x]=fa[fa[x]];
}
void Dfs3(LL u,LL ff){
for(LL i=head[u];i;i=dis[i].nxt){
LL v(dis[i].to); if(v==ff) continue;
Dfs3(v,u);
Union(v,u);
}
for(LL i=0;i<Qy[u].size();++i){
LL a(Qy[u][i].a),b(Qy[u][i].b);
if(a==u) a=b;
Find(a);
if(a!=fa[a]){
Ans[fa[a]].push_back(Qy[u][i]);
}
}
for(LL i=0;i<Ans[u].size();++i){
LL a(Ans[u][i].a),b(Ans[u][i].b),x(Ans[u][i].x),y(Ans[u][i].y),id(Ans[u][i].id);
Find(a); Find(b);
if(u!=a && u!=b) ans[id]=std::min(g[u][0]+h[a][0][x]+h[b][0][y]-f[u][0],g[u][1]+h[a][1][x]+h[b][1][y]-f[u][1]);
else{
if(u!=a) std::swap(a,b),std::swap(x,y);
ans[id]=g[a][x]+h[b][x][y];
}
}
}
int main(){
// freopen("testdata.in","r",stdin);
n=Read(); q=Read(); scanf(" %s",s+1);
for(LL i=1;i<=n;++i) p[i]=Read();
for(LL i=1;i<n;++i){
LL u(Read()),v(Read()); Add(u,v); Add(v,u);
}
Dfs1(1,0); Dfs2(1,0);
for(LL i=1;i<=q;++i){
LL a(Read()),x(Read()),b(Read()),y(Read());
Qy[a].push_back((qy){a,x,b,y,i}); Qy[b].push_back((qy){a,x,b,y,i});
}
for(LL i=1;i<=n;++i) fa[i]=i;
Dfs3(1,0);
for(LL i=1;i<=q;++i){
if(ans[i]>=inf) puts("-1");
else printf("%lld\n",ans[i]);
}
return 0;
}

P5024 保卫王国(动态dp/整体dp/倍增dp)的更多相关文章

  1. P5024 保卫王国[倍增+dp]

    窝当然不会ddp啦,要写这题当然是考虑优化裸dp啦,但是这题非常麻烦,于是变成了黑题. 首先,这个是没有上司的舞会模型,求图的带权最大独立集. 不考虑国王的限制条件,有 \[ dp[x][0]+=dp ...

  2. [倍增][换根DP]luogu P5024 保卫王国

    题面 https://www.luogu.com.cn/problem/P5024 分析 可以对有限制的点对之间的链进行在倍增上的DP数组合并. 需要通过一次正向树形DP和一次换根DP得到g[0][i ...

  3. luogu5024 [NOIp2018]保卫王国 (动态dp)

    可以直接套动态dp,但因为它询问之间相互独立,所以可以直接倍增记x转移到fa[x]的矩阵 #include<bits/stdc++.h> #define CLR(a,x) memset(a ...

  4. JZOJ5966. [NOIP2018TGD2T3] 保卫王国 (动态DP做法)

    题目大意 这还不是人尽皆知? 有一棵树, 每个节点放军队的代价是\(a_i\), 一条边连接的两个点至少有一个要放军队, 还有\(q\)次询问, 每次规定其中的两个一定需要/不可放置军队, 问这样修改 ...

  5. 【NOIP2018】保卫王国 动态dp

    此题场上打了一个正确的$44pts$,接着看错题疯狂$rush$“正确”的$44pts$,后来没$rush$完没将之前的代码$copy$回去,直接变零分了..... 这一题我们显然有一种$O(nm)$ ...

  6. luoguP5024 保卫王国 动态dp

    题目大意: emmmmm 题解: QAQ #include <cstdio> #include <cstring> #include <iostream> usin ...

  7. LuoguP5024 保卫王国(动态DP,LCT)

    最小权覆盖集 = 全集 - 最大权独立集 强制取点.不取点可以使用把权值改成正无穷或负无穷实现 接下来就是经典的"动态最大权独立集"了 O(nlogn). 这不是我说的,是immo ...

  8. BZOJ 5466: [Noip2018]保卫王国 动态DP

    Code: // luogu-judger-enable-o2 #include<bits/stdc++.h> #define ll long long #define lson (now ...

  9. 【洛谷】P5024 保卫王国 (倍增)

    前言 传送门 很多人写了题解了,我就懒得写了,推荐一篇博客 那就分享一下我的理解吧(说得好像有人看一样 对于每个点都只有选与不选两种情况,所以直接用倍增预处理出来两种情况的子树之内,子树之外的最值,最 ...

随机推荐

  1. Jest did not exit one second after the test run has completed.

    使用 Jest 进行单元测试时出现如下问题: Jest did not exit one second after the test run has completed. This usually m ...

  2. Oracle 创建数据表

    数据库中的每一个表都被一个模式(或用户)所拥有,因此表是一种典型的模式对象.在创建数据表时,Oracle 将在一个指定的表空间中为其分配存储空间.最初创建的表时一个空的逻辑存储结构,其中不包含任何数据 ...

  3. Mac 修改hostname

    mac终端上输入命令: sudo scutil --set HostName newname # 实例 sudo scutil --set HostName master

  4. 【JUC】7.CountDownLatch

    Latch:门闩.一种线程通信的方式:当程序不涉及同步,仅仅需要线程通信的时候,使用synchronize或者lock的线程通信等待唤醒机制,就显得太重了: 这时候,可以考虑使用信号量类:CountD ...

  5. HTML&CSS基础-伪类选择器

    HTML&CSS基础-伪类选择器 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.html源代码 <!DOCTYPE html> <html> & ...

  6. 介绍一个二次排序的小技巧(best coder27期1001jump jump jump)

    先来描述一下问题: 问题描述 有n小孩在比赛跳远,看谁跳的最远.每个小孩可以跳3次,这个小孩的成绩就是三次距离里面的最大值.例如,一个小孩跳3次的距离分别时10, 30和20,那么这个小孩的成绩就是3 ...

  7. 解决问题:Jupyter Notebook启动不会自动打开浏览器,每次都要自己打开浏览器输入网址

    1.找到anaconda下的anaconda prompt并打开(或者CMD)都可以 2.在anaconda prompt里面输入:jupyter notebook --generate-config ...

  8. 《CoderXiaoban》第八次团队作业:Alpha冲刺 3

    项目 内容 这个作业属于哪个课程 任课教师博客主页链接 这个作业的要求在哪里 实验十二 团队作业8:软件测试与ALPHA冲刺 团队名称 Coderxiaoban团队 作业学习目标 (1)掌握软件测试基 ...

  9. BZOJ1396 识别子串 和 BZOJ2865 字符串识别

    字符串识别 2865: 字符串识别 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 839  Solved: 261[Submit][Status][D ...

  10. Django示例演示--?

    引用自:https://blog.csdn.net/weixin_42950386/article/details/83143293 定义模型类 模型类被定义在"应用/models.py&q ...