保卫王国

题目描述

Z 国有\(n\)座城市,\(n - 1\)条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达。

Z 国的国防部长小 Z 要在城市中驻扎军队。驻扎军队需要满足如下几个条件:

  • 一座城市可以驻扎一支军队,也可以不驻扎军队。
  • 由道路直接连接的两座城市中至少要有一座城市驻扎军队。
  • 在城市里驻扎军队会产生花费,在编号为i的城市中驻扎军队的花费是\(p_i\)。

小 Z 很快就规划出了一种驻扎军队的方案,使总花费最小。但是国王又给小 Z 提出 了\(m\)个要求,每个要求规定了其中两座城市是否驻扎军队。小 Z 需要针对每个要求逐一 给出回答。具体而言,如果国王提出的第\(j\)个要求能够满足上述驻扎条件(不需要考虑 第 \(j\) 个要求之外的其它要求),则需要给出在此要求前提下驻扎军队的最小开销。如果 国王提出的第\(j\)个要求无法满足,则需要输出\(-1 (1 ≤ j ≤ m)\)。现在请你来帮助小 Z。

输入输出格式

输入格式:

第 1 行包含两个正整数\(n,m\)和一个字符串\(type\),分别表示城市数、要求数和数据类型。\(type\)是一个由大写字母 A,B 或 C 和一个数字 1,2,3 组成的字符串。它可以帮助你获得部分分。你可能不需要用到这个参数。这个参数的含义在【数据规模与约定】中 有具体的描述。

第 2 行\(n\)个整数\(p_i\),表示编号ii的城市中驻扎军队的花费。

接下来\(n - 1\)行,每行两个正整数\(u,v\),表示有一条\(u\)到\(v\)的双向道路。

接下来\(m\)行,第\(j\)行四个整数\(a,x,b,y(a ≠ b)\)),表示第\(j\)个要求是在城市\(a\)驻扎\(x\)支军队, 在城市\(b\)驻扎\(y\)支军队。其中,\(x\) 、 \(y\) 的取值只有 0 或 1:若 \(x\) 为 0,表示城市 \(a\) 不得驻 扎军队,若 \(x\) 为 1,表示城市 \(a\) 必须驻扎军队;若 \(y\)为 0,表示城市$ b$不得驻扎军队, 若 $y $为 1,表示城市 \(b\) 必须驻扎军队。

输入文件中每一行相邻的两个数据之间均用一个空格分隔。

输出格式:

输出共 \(m\) 行,每行包含 1 个整数,第\(j\)行表示在满足国王第\(j\)个要求时的最小开销, 如果无法满足国王的第\(j\)个要求,则该行输出 -1。

输入输出样例

输入样例#1:

5 3 C3

2 4 1 3 9

1 5

5 2

5 3

3 4

1 0 3 0

2 1 3 1

1 0 5 0

输出样例#1:

12

7

-1

说明

【样例解释】

对于第一个要求,在 4 号和 5 号城市驻扎军队时开销最小。

对于第二个要求,在 1 号、2 号、3 号城市驻扎军队时开销最小。

第三个要求是无法满足的,因为在 1 号、5 号城市都不驻扎军队就意味着由道路直接连 接的两座城市中都没有驻扎军队。

【数据规模与约定】

对于\(100\%\)的数据,\(n,m ≤ 100000,1 ≤ p_i ≤ 100000\)。



数据类型的含义:

A:城市i与城市i + 1直接相连。

B:任意城市与城市 1 的距离不超过 100(距离定义为最短路径上边的数量),即如果这 棵树以 1 号城市为根,深度不超过 100。

C:在树的形态上无特殊约束。

1:询问时保证a = 1,x = 1,即要求在城市 1 驻军。对b,y没有限制。

2:询问时保证a,b是相邻的(由一条道路直接连通)

3:在询问上无特殊约束。

分析

考虑没有修改时的做法,设\(f[x][1/0]\)表示\(x\)选不选的最小花费,转移:

\[f[x][1]=\sum \min\{f[y][0],f[y][1]\} \\
f[x][0]=\sum f[y][1]
\]

现在有强制取舍,考虑可以把权值减加\(\infty\)来处理(注意这里写成赋值较麻烦),所以要实现的就是一个带点权修改的动态DP。类似的定义除去重儿子的贡献的\(g\)数组。

重定义矩乘运算中的乘法为加法,求和为取min,则转移方程为:

\[\left(
\begin{matrix}
+\infty & g[i][0] \\
g[i][1] & g[i][1]
\end{matrix}
\right)*
\left(
\begin{matrix}
f[i+1][0] \\
f[i+1][1]
\end{matrix}
\right)=
\left(
\begin{matrix}
f[i][0] \\
f[i][1]
\end{matrix}
\right)
\]

注意转移前后\(f\)中的下标位置要一致。并且在叶子节点的时候,转移矩阵里的\(+\infty\)要赋成0,这样才能代表\(f[leaf][0]\)。

时间复杂度\(O(n+m \log^2 n)\)

#include<bits/stdc++.h>
#define rg register
#define il inline
#define co const
template<class T>il T read(){
rg T data=0,w=1;
rg char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') w=-1;
ch=getchar();
}
while(isdigit(ch))
data=data*10+ch-'0',ch=getchar();
return data*w;
}
template<class T>il T read(rg T&x){
return x=read<T>();
}
typedef long long ll;
using namespace std; co ll N=1e5+5,INF=1e10;
int n,m,a[N];
int ecnt,adj[N],nxt[2*N],go[2*N];
int fa[N],son[N],sze[N],top[N],idx[N],pos[N],tot,ed[N];
ll f[N][2];
struct matrix{
ll g[2][2];
matrix(){for(int i=0;i<2;++i)for(int j=0;j<2;++j)g[i][j]=INF;}
matrix operator*(co matrix&b)co{
matrix c;
for(int i=0;i<2;++i)
for(int j=0;j<2;++j)
for(int k=0;k<2;++k)
c.g[i][j]=min(c.g[i][j],g[i][k]+b.g[k][j]);
return c;
}
}val[N],data[4*N]; void add(int u,int v){
go[++ecnt]=v,nxt[ecnt]=adj[u],adj[u]=ecnt;
}
void init(){
static int que[N];
que[1]=1;
for(int ql=1,qr=1;ql<=qr;++ql)
for(int u=que[ql],e=adj[u],v;e;e=nxt[e])
if((v=go[e])!=fa[u])
fa[v]=u,que[++qr]=v;
for(int qr=n,u;qr;--qr){
sze[u=que[qr]]++;
sze[fa[u]]+=sze[u];
if(sze[u]>sze[son[fa[u]]]) son[fa[u]]=u;
}
for(int ql=1,u;ql<=n;++ql)
if(!top[u=que[ql]]){
for(int v=u;v;v=son[v])
top[v]=u,idx[pos[v]=++tot]=v;
ed[u]=tot;
}
for(int qr=n,u;qr;--qr){
u=que[qr];
f[u][1]=a[u];
for(int e=adj[u],v;e;e=nxt[e])
if(v=go[e],v!=fa[u]){
f[u][0]+=f[v][1];
f[u][1]+=min(f[v][0],f[v][1]);
}
}
} void build(int k,int l,int r){
if(l==r){
ll g0=0,g1=a[idx[l]];
for(int u=idx[l],e=adj[u],v;e;e=nxt[e])
if((v=go[e])!=fa[u]&&v!=son[u])
g0+=f[v][1],g1+=min(f[v][0],f[v][1]);
data[k].g[0][0]=l==ed[top[idx[l]]]?0:INF,data[k].g[0][1]=g0; // edit 2:leaf init to be 0
data[k].g[1][0]=g1,data[k].g[1][1]=g1;
val[l]=data[k];
return;
}
int mid=l+r>>1;
build(k<<1,l,mid);
build(k<<1|1,mid+1,r);
data[k]=data[k<<1]*data[k<<1|1];
}
void change(int k,int l,int r,int p){
if(l==r){
data[k]=val[l];
return;
}
int mid=l+r>>1;
if(p<=mid) change(k<<1,l,mid,p);
else change(k<<1|1,mid+1,r,p);
data[k]=data[k<<1]*data[k<<1|1];
}
matrix query(int k,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr) return data[k];
int mid=l+r>>1;
if(qr<=mid) return query(k<<1,l,mid,ql,qr);
if(ql>mid) return query(k<<1|1,mid+1,r,ql,qr);
return query(k<<1,l,mid,ql,qr)*query(k<<1|1,mid+1,r,ql,qr);
}
matrix ask(int u){
return query(1,1,n,pos[top[u]],ed[top[u]]);
}
void path_change(int u,ll x){
val[pos[u]].g[1][0]+=x,val[pos[u]].g[1][1]+=x; // edit 1:+-INF
matrix od,nw;
while(u){
od=ask(top[u]);
change(1,1,n,pos[u]);
nw=ask(top[u]);
u=fa[top[u]];
val[pos[u]].g[0][1]+=nw.g[1][0]-od.g[1][0];
val[pos[u]].g[1][0]+=min(nw.g[0][0],nw.g[1][0])-min(od.g[0][0],od.g[1][0]);
val[pos[u]].g[1][1]=val[pos[u]].g[1][0];
}
}
int main(){
// freopen(".in","r",stdin);
// freopen(".out","w",stdout);
read(n),read(m),read<int>();
for(int i=1;i<=n;++i) read(a[i]);
for(int i=1,u,v;i<n;++i)
read(u),read(v),add(u,v),add(v,u);
init();
build(1,1,n);
matrix t;
for(int a,x,b,y;m--;){
read(a),read(x),read(b),read(y);
if(!x&&!y&&(fa[a]==b||fa[b]==a)) {puts("-1");continue;}
path_change(a,x?-INF:INF),path_change(b,y?-INF:INF);
t=ask(1);
printf("%lld\n",min(t.g[0][0],t.g[1][0])-(x?-INF:0)-(y?-INF:0));
path_change(a,x?INF:-INF),path_change(b,y?INF:-INF);
}
return 0;
}

后记

这题,我在考场上看都没看……L巨说这题暴力有44分,失策了。

LG5024 保卫王国的更多相关文章

  1. noip2018 d2t3 保卫王国 解题报告

    保卫王国 电脑卡懒得把题面挪过来了. 朴素 \[ dp_{i,0}=\sum dp_{s,1}\\ dp_{i,1}=\sum \min(dp_{s,0},dp_{s,1})+p_i \] 然后直接动 ...

  2. 「NOIP2018」保卫王国

    「NOIP2018保卫王国」 题目描述 有一棵 \(n\) 个点, 点有点权 \(a_i\),\(m\) 组询问, 每次求钦点两个节点必须选或者必须不选后的树上最小点覆盖. \(1 \leq n, m ...

  3. Uoj 441 保卫王国

    Uoj 441 保卫王国 动态 \(dp\) .今天才来写这个题. 设 \(f[u][0/1]\) 表示子树 \(u\) 中不选/选 \(u\) 时的最小权值和,显然有:\(f[u][0]=\sum ...

  4. 竞赛题解 - NOIP2018 保卫王国

    \(\mathcal{NOIP2018}\) 保卫王国 - 竞赛题解 按某一个炒鸡dalao名曰 taotao 的话说: \(\ \ \ \ \ \ \ \ \ "一道sb倍增题" ...

  5. [NOIP2018TG]保卫王国

    [NOIP2018TG]保卫王国 BZOJ luogu 当动态dp模板题写的,(全集-最大点权独立集)不能放军队的+inf,必须放军队-inf即可 注意矩阵乘法的顺序问题 #define ll lon ...

  6. 『保卫王国 树上倍增dp』

    保卫王国 Description Z 国有n座城市,n - 1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达. Z 国的国防部长小 Z 要在城市中驻扎军队.驻扎军队需 ...

  7. 【比赛】NOIP2018 保卫王国

    DDP模板题 #include<bits/stdc++.h> #define ui unsigned int #define ll long long #define db double ...

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

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

  9. NOIP2018保卫王国

    题目大意:给一颗有点权的树,每次规定两个点选还是不选,求这棵树的最小权点覆盖. 题解 ZZ码农题. 要用动态dp做,这题就是板子,然鹅并不会,留坑代填. 因为没有修改,所以可以静态倍增. 我们先做一遍 ...

随机推荐

  1. HDU4112

    对于n*m*k的方块,用手掰成1**1的那么搜需要的步骤是固定的,为n*m*k-,如果用刀切,因为可以把多块叠在一起切,所以对于长度为n的,将他切成0,所需要的步骤数位k 对于n*m*k的方块,用手掰 ...

  2. poj1985 / poj2631(树的直径)

    poj1985 Cow Marathon 树的直径裸题 树的直径的一般求法: 任意一点为起点,dfs/bfs找出与它最远的点$u$ 以$u$为起点,dfs/bfs找出与它最远的点$v$ 则$d(u,v ...

  3. 20145221 《Java程序设计》第五周学习总结

    20145221 <Java程序设计>第五周学习总结 教材学习内容总结 第八章部分 - 异常处理 语法与继承架构 使用try...catch 首先要明确一点:Java中所有错误都会打包为对 ...

  4. uboot 版本号生成过程

    uboot 版本号生成过程 uboot版本号貌似与实际开发不相关,但是我现在遇到一个bug与版本号关联密切. 这个bug与<uboot dm9000驱动故障>基本上是一样的,但是在上一篇博 ...

  5. 《EMCAScript6入门》读书笔记——14.Promise对象

  6. 创建一个 SQLite 数据库

    首先,我们学习如何创建一个SQLite 数据库.如果想要在data/example.sqlite 这个路径中创建一个示例数据库,就必须确保该路径存在.如果该路径不存在,就必须先创建路径:if (!di ...

  7. 使用 for 循环

    for 循环通过迭代一个给定向量或列表,重复执行某个表达式.for 循环的语法是这样的:for (var in vector) {expr}var 遍历 vector 中的各个元素值,expr 被反复 ...

  8. XML_CPP_资料_libXml2_01

    ZC: 看了一些 C/C++的XML文章,也看了一些 Qt的 QXmlQuery/QXmlSimpleReader/QXmlStreamReader/QXmlStreamWriter 的文章.总体感觉 ...

  9. JAVA技术分享:消失的线程

    很多小伙伴都问过我一个问题,就是任务线程跑着跑着消失了,而且没有任何异常日志.我都是条件反射式的回复,是不是用了线程池的submit提交任务.而且很大几率对方给予肯定答复. 解决方案,很多人都听过不少 ...

  10. mysql--------命令来操作表

    常用的通过mysql命令来更改表结构的一些sql语句,包括添加.删除.修改字段.调整字段顺序. 添加字段: alter table `user_movement_log` Add column Gat ...