noip2018luogu5024保卫王国

Posted paul-guderian

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip2018luogu5024保卫王国相关的知识,希望对你有一定的参考价值。

题目描述

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

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

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

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

输入输出格式

输入格式:

 

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

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

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

接下来 mm 行,第jj行四个整数a,x,b,y(a ≠ b)a,x,b,y(ab),表示第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个要求,则该行输出 -11

 

输入输出样例

输入样例#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,m100000,1pi?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,乘法定义成加法,转移写成矩阵:$$\
egin{pmatrix} f[son_{u}][0] & f[son_{u}][1] end{pmatrix} 
egin{pmatrix} infty & g[u][1] \ g[u][0] & g[u][1] end{pmatrix}
=
egin{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
",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
",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 }  
倍增

 

 

 

 

以上是关于noip2018luogu5024保卫王国的主要内容,如果未能解决你的问题,请参考以下文章

P5024 保卫王国

P5024 保卫王国[倍增+dp]

noip2018 d2t3 保卫王国 解题报告

P5024 保卫王国(动态dp/整体dp/倍增dp)

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

$NOIP 2018 Day2$ 模拟考试 题解报告