noip2018luogu5024保卫王国
Posted paul-guderian
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了noip2018luogu5024保卫王国相关的知识,希望对你有一定的参考价值。
题目描述
Z 国有n座城市,n−1条双向道路,每条双向道路连接两座城市,且任意两座城市 都能通过若干条道路相互到达。
Z 国的国防部长小 Z 要在城市中驻扎军队。驻扎军队需要满足如下几个条件:
- 一座城市可以驻扎一支军队,也可以不驻扎军队。
- 由道路直接连接的两座城市中至少要有一座城市驻扎军队。
- 在城市里驻扎军队会产生花费,在编号为i的城市中驻扎军队的花费是pi?。
小 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个整数pi?,表示编号i的城市中驻扎军队的花费。
接下来 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。
输入输出样例
说明
【样例解释】
对于第一个要求,在 4 号和 5 号城市驻扎军队时开销最小。
对于第二个要求,在 1 号、2 号、3 号城市驻扎军队时开销最小。
第三个要求是无法满足的,因为在 1 号、5 号城市都不驻扎军队就意味着由道路直接连 接的两座城市中都没有驻扎军队。
【数据规模与约定】
对于 100%的数据,n,m≤100000,1≤pi?≤100000。
数据类型的含义:
A:城市i与城市i+1直接相连。
B:任意城市与城市 1 的距离不超过 100(距离定义为最短路径上边的数量),即如果这 棵树以 1 号城市为根,深度不超过 100。
C:在树的形态上无特殊约束。
1:询问时保证a=1,x=1,即要求在城市 1 驻军。对b,y没有限制。
2:询问时保证a,b是相邻的(由一条道路直接连通)
3:在询问上无特殊约束。
题解:
首先一般的暴力$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保卫王国的主要内容,如果未能解决你的问题,请参考以下文章