题目描述
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