[硫化铂]中心城镇问题

Posted StaroForgin

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[硫化铂]中心城镇问题相关的知识,希望对你有一定的参考价值。

中心城镇问题


题解

实质上是一个非常经典的长链剖分dp题。

我们可以记 d p u , i dp_u,i dpu,i表示在以点 u u u为根节点的子树内,最深的特殊点深度为 i i i时总的权值最大值。
我们的转移主要分两个部分,合并两棵子树,与将当前子树的根节点赋为特殊点。

对于第一个转移,我们需要保证合并的两棵子树它们最浅的特殊点的距离是不小于 K K K的,转移式为
d p u , i = min ⁡ min ⁡ ( j , k ) = i ∧ j + k − 2 d e p u ⩾ K d p u , j + d p v , k dp_u,i=\\min_\\min(j,k)=i\\wedge j+k-2dep_u\\geqslant Kdp_u,j+dp_v,k dpu,i=min(j,k)=ij+k2depuKmindpu,j+dpv,k但这样需要枚举 j , k j,k j,k两个,显然是会 T T T飞的,但我们观察到上面的状态是可以通过后缀最大值优化的,我们将 d p u , i dp_u,i dpu,i的定义换成在以点 u u u为根的子树内,最深的特殊点深度不小于 i i i时总权值的最大值。
d p u , i = min ⁡ ( d p u , i + d p v , d e p u + K − i , d p v , i + d p u , d e p u + K − i ) dp_u,i=\\min(dp_u,i+dp_v,dep_u+K-i,dp_v,i+dp_u,dep_u+K-i) dpu,i=min(dpu,i+dpv,depu+Ki,dpv,i+dpu,depu+Ki)但这样实际上转移后并没有真正使得转移后的 d p u , i dp_u,i dpu,i表示上个定义 d p u , i dp_u,i dpu,i的后缀最大值,由于它限制了 j j j是被累积到 i i i上的,势必会使得该 j j j的转移范围减少,也就是说存在 j + k ⩾ K + 2 d e p u > i + K j+k\\geqslant K+2dep_u>i+K j+kK+2depu>i+K的情形。
面对这种情况,我们不妨在转移后再做一次后缀最小值,显然在合并这两棵子树后,如果 v v v中有特殊点,即有贡献的话,我们影响到的 d p u , i dp_u,i dpu,i i i i一定是不会超过 v v v子树中最深节点的深度的。故我们做的后缀最大值的时间复杂度与前面转移的时间复杂度都是 O ( max ⁡ v ′ ∈ T v d e p v ) O\\left(\\max_v'\\in T_vdep_v\\right) O(maxvTvdepv)的,即最长链长度。
既然如此,我们就可以联想到通过长链剖分来优化我们的 d p dp dp转移,每次把短的链合并到长的链上。

第二部分的转移就是再将我们当前的 u u u赋为特殊点,显然这种情况需要保证已有的特殊点都与 u u u距离不小于 K K K,即深度都不小于 d e p u + K dep_u+K depu+K,我们的 d p dp dp又是维护的后缀最大值,有转移式,
d p u , d e p u = v a l u + d p u , d e p u + K dp_u,dep_u=val_u+dp_u,dep_u+K dpu,depu=valu+dpu,depu+K这种转移显然是 O ( 1 ) O\\left(1\\right) O(1)的,它现在是在最前面的,并不会影响其它的后缀。

整个就是一个长链剖分优化 d p dp dp的过程,每条链只会产生一次贡献,之后就被并到长链上了,以后就是长链产生贡献,是 O ( n ) O\\left(n\\right) O(n)的。不过重链剖分也可以过,可能时间复杂度与空间复杂度不大一样。

时间复杂度 O ( n ) O\\left(n\\right) O(n)(长链)或 O ( n log ⁡   n ) O\\left(n\\log\\,n\\right) O(nlogn)(重链)。

源码

#include<bits/stdc++.h>
using namespace std;
#define MAXN 1000005
#define lowbit(x) (x&-x)
#define reg register
#define pb push_back
#define mkpr make_pair
#define fir first
#define sec second
#define lson (rt<<1)
#define rson (rt<<1|1)
typedef long long LL;
typedef unsigned long long uLL; 
typedef long double ld;
typedef pair<int,int> pii;
const int INF=0x3f3f3f3f;
const int mo=1e9+7;
const int mod=1e5+3;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=2000;
const int n1=1000;
const int M=100000;
const int orG=3,ivG=332748118;
const long double Pi=acos(-1.0);
const double eps=1e-12;
template<typename _T>
_T Fabs(_T x)return x<0?-x:x;
template<typename _T>
void read(_T &x)
	_T f=1;x=0;char s=getchar();
	while(s>'9'||s<'0')if(s=='-')f=-1;s=getchar();
	while('0'<=s&&s<='9')x=(x<<3)+(x<<1)+(s^48);s=getchar();
	x*=f;

template<typename _T>
void print(_T x)if(x<0)x=(~x)+1;putchar('-');if(x>9)print(x/10);putchar(x%10+'0');
int gcd(int a,int b)return !b?a:gcd(b,a%b);
int add(int x,int y,int p)return x+y<p?x+y:x+y-p;
void Add(int &x,int y,int p)x=add(x,y,p);
int qkpow(int a,int s,int p)int t=1;while(s)if(s&1)t=1ll*t*a%p;a=1ll*a*a%p;s以上是关于[硫化铂]中心城镇问题的主要内容,如果未能解决你的问题,请参考以下文章

[硫化铂]货币

[硫化铂]签到题

[硫化铂]二十

[硫化铂]守序划分问题

[硫化铂]好

[硫化铂]传染