【noip2018】【luogu5024】保卫王国

题目描述

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

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

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

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

输入输出格式

输入格式:

第 11 行包含两个正整数n,mn,m和一个字符串typetype,分别表示城市数、要求数和数据类型。typetype是一个由大写字母 AA,BB 或 CC 和一个数字 11,22,33 组成的字符串。它可以帮助你获得部分分。你可能不需要用到这个参数。这个参数的含义在【数据规模与约定】中 有具体的描述。

第 22 行nn个整数p_ipi?,表示编号ii的城市中驻扎军队的花费。

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

接下来 mm 行,第jj行四个整数a,x,b,y(a ≠ b)a,x,b,y(a≠b),表示第jj个要求是在城市aa驻扎xx支军队, 在城市bb驻扎yy支军队。其中,xx 、 yy 的取值只有 00 或 11:若 xx 为 00,表示城市 aa 不得驻 扎军队,若 xx 为 11,表示城市 aa 必须驻扎军队;若 yy为 00,表示城市 bb不得驻扎军队, 若 yy为 11,表示城市 bb 必须驻扎军队。

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

输出格式:

输出共 mm 行,每行包含 11 个整数,第jj行表示在满足国王第jj个要求时的最小开销, 如果无法满足国王的第jj个要求,则该行输出 -1−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

说明

【样例解释】

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

对于第二个要求,在 11 号、22 号、33 号城市驻扎军队时开销最小。

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

【数据规模与约定】

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

数据类型的含义:

AA:城市ii与城市i + 1i+1直接相连。
BB:任意城市与城市 11 的距离不超过 100100(距离定义为最短路径上边的数量),即如果这 棵树以 11 号城市为根,深度不超过 100100。
CC:在树的形态上无特殊约束。
11:询问时保证a = 1,x = 1a=1,x=1,即要求在城市 11 驻军。对b,y没有限制。
22:询问时保证a,ba,b是相邻的(由一条道路直接连通)
33:在询问上无特殊约束。

题解:

首先一般的暴力$dp[u][0] = \sum dp[v][1]$ , $dp[u][1]  = \sum min(dp[v][0],dp[v][1]) + a[u]$

复杂度$O(n^2)$

考虑倍增优化  :

fa[u][i]表示u向上跳2^i的祖先,然后用f[u][i]表示以fa[u][i]为根节点,不包括u的子树的最优dp值;

将f[u][i]写成一个2*2的矩阵,表示fa[u][i]和u是否选择;

更新一个点u,直接从u倍增到根节点就可以了;

考虑同时更新u和v,先跳到他们lca的儿子,再从lca跳到根,分类合并一下三个矩阵;

注意特判v和u有祖先关系的情况;

LCT做法:
      其实这东西似乎叫动态dp

一般套路是将转移写成矩阵然后用数据结构维护;

树链剖分后 f[u][0/1]表示u为根的子树dp值,g[u][0/1]表示u为根的子树除开重儿子($son_{u}$)的dp值;

$f[u][0] = g[u][0] + f[son_{u}][1] $  ,

$f[u][1] = g[u][1] + min( f[son_{u}][0] , f[son_{u}][1] ) $

将加法定义成取min,乘法定义成加法,转移写成矩阵:$$\\
\begin{pmatrix} f[son_{u}][0] & f[son_{u}][1] \end{pmatrix}  \
\begin{pmatrix} \infty & g[u][1] \\ g[u][0] & g[u][1] \end{pmatrix}
=
\begin{pmatrix} f[u][0] & f[u][1] \end{pmatrix}
$$

用LCT维护(只写了倍增,后面补上)

另外推荐一个动态dp的题:http://noi.ac/problem/111

  1 #include<bits/stdc++.h>
  2 #define il inline
  3 #define rg register
  4 #define ll long long
  5 using namespace std;
  6 const int N=100010;
  7 ll inf=1e15;
  8 struct mat{
  9     ll c[2][2];
 10     mat(ll _a=inf,ll _b=inf,ll _c=inf,ll _d=inf){
 11         c[0][0]=_a;c[0][1]=_b;
 12         c[1][0]=_c;c[1][1]=_d;
 13     }
 14     mat operator *(const mat&A){
 15         mat ret;
 16         for(int i=0;i<2;i++)
 17         for(int j=0;j<2;j++){
 18             ret.c[i][j]=min(inf,min(c[i][0]+A.c[0][j],c[i][1]+A.c[1][j]));
 19         }
 20         return ret;
 21     }
 22 }f[N][18];
 23 char gc(){
 24     static char*p1,*p2,s[1000000];
 25     if(p1==p2)p2=(p1=s)+fread(s,1,1000000,stdin);
 26     return(p1==p2)?EOF:*p1++;
 27 }
 28 int rd(){
 29     int x=0; char c=gc();
 30     while(c<‘0‘||c>‘9‘)c=gc();
 31     while(c>=‘0‘&&c<=‘9‘)x=(x<<1)+(x<<3)+c-‘0‘,c=gc();
 32     return x;
 33 }
 34 int n,m,o,hd[N];
 35 ll a[N],dep[N],fa[N][18],bin[18],dp[N][2];
 36 struct Edge{int v,nt;}E[N<<1];
 37 void adde(int u,int v){
 38     E[o]=(Edge){v,hd[u]};hd[u]=o++;
 39     E[o]=(Edge){u,hd[v]};hd[v]=o++;
 40 }
 41 void dfs0(int u,int F){
 42     dp[u][0]=0;dp[u][1]=a[u];
 43     for(rg int i=hd[u];~i;i=E[i].nt){
 44         int v=E[i].v;
 45         if(v==F)continue;
 46         dfs0(v,u);
 47         dp[u][0]+=dp[v][1];
 48         dp[u][1]+=min(dp[v][0],dp[v][1]);
 49     }
 50 }
 51 void dfs(int u,int F){
 52     dep[u]=dep[fa[u][0]=F]+1;
 53     f[u][0]=mat(
 54         inf,
 55         dp[fa[u][0]][0]-dp[u][1],
 56         dp[fa[u][0]][1]-min(dp[u][0],dp[u][1]),
 57         dp[fa[u][0]][1]-min(dp[u][0],dp[u][1])
 58     );
 59     for(rg int i=1;bin[i]<dep[u];i++){
 60         fa[u][i]=fa[fa[u][i-1]][i-1];
 61         f[u][i]=f[fa[u][i-1]][i-1]*f[u][i-1];
 62     }
 63     for(rg int i=hd[u];~i;i=E[i].nt){
 64         int v=E[i].v;
 65         if(v==F)continue;
 66         dfs(v,u);
 67     }
 68 }
 69 void solve(int u,int x,int v,int y){
 70     if(dep[u]<dep[v])swap(u,v),swap(x,y);
 71     mat tu,tv,t;
 72     tu=mat(dp[u][0],inf,inf,dp[u][1]);
 73     tv=mat(dp[v][0],inf,inf,dp[v][1]);
 74     for(int i=0;i<18;i++)if(bin[i]&(dep[u]-dep[v])){
 75         tu=f[u][i]*tu;
 76         u=fa[u][i];
 77     }
 78     if(u==v){
 79         ll ans;
 80         t=mat(0,inf,inf,0);
 81         for(int i=0;i<18;i++)if(bin[i]&(dep[u]-1)){
 82             t=f[u][i]*t;
 83             u=fa[u][i];
 84         }
 85         ans= min(t.c[0][y],t.c[1][y])+tu.c[y][x];
 86         if(ans>=inf)puts("-1");
 87         else printf("%lld\n",ans);
 88         return;
 89     }
 90     for(int i=17;~i;i--)if(fa[u][i]!=fa[v][i]){
 91         tu=f[u][i]*tu;
 92         tv=f[v][i]*tv;
 93         u=fa[u][i];
 94         v=fa[v][i];
 95     }
 96     t=mat(
 97         dp[fa[u][0]][0]-dp[u][1]-dp[v][1],
 98         inf,
 99         inf,
100         dp[fa[u][0]][1]-min(dp[u][0],dp[u][1])-min(dp[v][0],dp[v][1])
101     );
102     u=fa[u][0];
103     for(int i=0;i<18;i++)if(bin[i]&(dep[u]-1)){
104         t=f[u][i]*t;
105         u=fa[u][i];
106     }
107     ll ans=inf;
108     ans = min(
109         min(t.c[0][0],t.c[1][0])+tu.c[1][x]+tv.c[1][y],
110         min(t.c[0][1],t.c[1][1])+min(tu.c[0][x],tu.c[1][x])+min(tv.c[0][y],tv.c[1][y])
111     );
112     if(ans>=inf)puts("-1");
113     else printf("%lld\n",ans);
114 }
115 int main(){
116     freopen("defense.in","r",stdin);
117     freopen("defense.out","w",stdout);
118     n=rd(); m=rd(); gc(); gc();
119     for(rg int i=bin[0]=1;i<18;i++)bin[i]=bin[i-1]<<1;
120     for(rg int i=1;i<=n;i++)a[i]=rd(),hd[i]=-1;
121     for(rg int i=1;i<n;i++)adde(rd(),rd());
122     dfs0(1,0);
123     dfs(1,0);
124     for(rg int i=1,u,v,x,y;i<=m;i++){
125         u=rd();x=rd();v=rd();y=rd();
126         solve(u,x,v,y);
127     }
128     return 0;
129 }  

倍增

原文地址:https://www.cnblogs.com/Paul-Guderian/p/10014616.html

时间: 2024-07-30 07:37:49

【noip2018】【luogu5024】保卫王国的相关文章

[luogu 5024] 保卫王国

luogu 5024(保卫王国) Problem Here Solution 这大概是一篇重复累赘的blog吧. 最小覆盖集=全集-最大独立集 强制取或不取,可以通过将权值修改成inf或者-inf 然后就用动态dp的套路就行了 #include<bits/stdc++.h> #define ll long long #define max(a,b) ((a)>(b)?(a):(b)) #define min(a,b) ((a)<(b)?(a):(b)) inline ll read

P5024 保卫王国

——————————————————————————————————————————————- 考前练习打打部分分 设置权值这个方法需要记住 ———————————————————————————————————————————————————— PT:44 ———— #include<bits/stdc++.h> using namespace std; const int inf=1000000000; char ch[5]; int n,m,head[101000],ne,a,b,c,d

LuoguP5024 保卫王国(动态DP,树形DP,矩阵加速,LCT)

最小权覆盖集 = 全集 - 最大权独立集 强制取点.不取点可以使用把权值改成正无穷或负无穷实现 接下来就是经典的"动态最大权独立集"了 O(nlogn). 这不是我说的,是immortalCO大佬说的 于是我调了一万年极值,终在\(\frac{LLONG\_MAX}{3}\)时\(11s\)卡过... 知道最小权覆盖集 = 全集 - 最大权独立集,就是模板\(DDP\)了 #include <cstdio> #include <iostream> #includ

P5024 保卫王国[倍增+dp]

窝当然不会ddp啦,要写这题当然是考虑优化裸dp啦,但是这题非常麻烦,于是变成了黑题. 首先,这个是没有上司的舞会模型,求图的带权最大独立集. 不考虑国王的限制条件,有 \[ dp[x][0]+=dp[y][1]\dp[x][1]+=min(dp[y][1],dp[y][0]) \] 现在考虑限制条件,如果对每一个限制条件都做一次dp,复杂度达到\(O(n^2)\),无法承受. 显然,对于这些限制条件,每一次的变动不会影响其它大多数的状态. 对于一个限制条件,我们分开考虑,先考虑只对一个城市进行

noip历年试题

noip2018 铺设道路 货币系统 赛道修建 一眼贪心.随便实现. 旅行 环套树枚举删除环上哪条边. 填数游戏 找规律,这谁会啊. 保卫王国 动态Dp,去问这位神仙. noip2017 小凯的疑惑 就是数论结论题,当然也可以找规律. 时间复杂度 原理都懂,大模拟. 逛公园 SPFA还没死.jpg 奶酪 宝藏 状压Dp. 列队 我太懒了直接Splay模拟. noip2016 玩具谜题 天天爱跑步 考虑一条链怎么做(随便做),然后树上同理. 换教室 组合数问题 蚯蚓 拿两个队列来归并. 愤怒的小鸟

【考试】10.2

1>保卫王国 一棵树,有点权, 树上一条边上要求至少一个点被选, 现在有好多个询问,要求一个点被选,或者没有被选 求问每个询问的最小代价 (1)很明显的树形dp, 简单的暴力,对每次询问,求一次dp,用dfs 复杂度O(nm) 前11个点,44分 (2)优化dp 因为m优化不得,离线也没什么用, 所以,估计最终的复杂度应该是O(mlogn) 再画一棵树,发现每次影响的其实只有x到y这一段中的dp, (当然相邻节点有一点...影响) 我们把要更新的部分分成三部分: 设两个点为u,v,t=LCA(u

我爱OI(来自一个年老但是毫无成就的IOer的退役感言)

某盆终于退役了... 这可能是本博客的最后一篇文章了吧... 如果不,那就还有两个方向: 1.自己闲得无聊学学算法 2.当成自己的随笔博客不知道该干些什么了.AFO了. 然后呢?该扯点什么了?? 额说到这,想起来我们也学了4年OI了吧 从第一年的暑假,78人,坐在实验的大机房里,每人带一瓶冰块, 到第二年的50人,分布在沈老师的五个班里, 再到仅剩的20人,分布在一中二中, 渐渐的,只剩下9人依旧奋战在一线, 一次意外,我们的团队又少了一个人——bk201. 一路经历了多少? 四次集训,分布全国

模版 动态 dp

模版 动态 dp 终于来写这个东西了.. LG 模版:给定 n 个点的数,点有点权, $ m $ 次修改点权,求修改完后这个树的最大独立集大小. 我们先来考虑朴素的最大独立集的 dp \[ dp[u][0] = \sum_v max\{dp[v][1],dp[v][0]\}\\dp[u][1] = val[u] + \sum_v dp[v][0] \] 现在我们就拥有了一个 $ O(nm) $ 的做法,但是明显它不优秀. 既然支持修改,我们可以考虑树剖(或者LCT),现在树被我们剖成了重链和轻链

京东笔试编程题:采购单+保卫方案

采购单时间限制:C/C++语言 1000MS:其他语言 3000MS内存限制:C/C++语言 65536KB:其他语言 589824KB题目描述:过年啦!小B高兴的不行了,她收到了很多红包,可以实现好多的愿望呢.小B可是对商店货架上心仪的货物红眼好久了,只因囊中羞涩作罢,这次她可是要大大的shopping一番.小B想去购物时,总是习惯性的把要买的东西列在一个购买清单上,每个物品单独列一行(即便要买多个某种物品),这次也不例外.小B早早的来到了商店,由于她太激动,以至于她到达商店的时候,服务员还没