[AGC008F]Black Radius
Posted StaroForgin
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[AGC008F]Black Radius相关的知识,希望对你有一定的参考价值。
Black Radius
题解
首先考虑以一个点为根向外扩展会得到多少种不同的情形,显然以一个点为根的情况除了全部都染了应该都是不同的,所以情况数有以它为根时最深的点深度
−
1
-1
−1种。
但为什么我们不能将1其直接加起来作为总答案呢?当然是因为有几种情况它们得到的结果是一样的。
我们记
f
(
i
,
j
)
f(i,j)
f(i,j)表示以点
i
i
i为根,将深度不超过
j
j
j的点全部染黑得到的树的状况。
可以发现,如果
f
(
x
,
d
1
)
f(x,d_1)
f(x,d1)与
f
(
y
,
d
2
)
f(y,d_2)
f(y,d2)的树状况一致,那么对于在
x
,
y
x,y
x,y的简单路径上的点
z
z
z,一定存在一个
d
d
d使得
f
(
z
,
d
)
=
f
(
x
,
d
1
)
=
f
(
y
,
d
2
)
f(z,d)=f(x,d_1)=f(y,d_2)
f(z,d)=f(x,d1)=f(y,d2)。
由于我们的
f
(
x
,
d
1
)
f(x,d_1)
f(x,d1)与
f
(
y
,
d
2
)
f(y,d_2)
f(y,d2)相同,那么一定有在
x
,
y
x,y
x,y的简单路径上,只有一个节点的子树不是全黑的,否则
x
,
y
x,y
x,y一定在其中一个子树上染色状况不同。
对于路径上的点
z
z
z,如果它的子树不是全黑,那么一定满足
d
1
−
d
i
s
(
x
,
z
)
=
d
2
−
d
i
s
(
y
,
z
)
d_1-dis(x,z)=d_2-dis(y,z)
d1−dis(x,z)=d2−dis(y,z),由于
d
i
s
(
x
,
z
)
+
d
i
s
(
y
,
z
)
dis(x,z)+dis(y,z)
dis(x,z)+dis(y,z)为定值
d
i
s
(
x
,
y
)
dis(x,y)
dis(x,y)所以满足上面条件的
z
z
z的
d
i
s
(
x
,
z
)
dis(x,z)
dis(x,z)与
d
i
s
(
y
,
z
)
dis(y,z)
dis(y,z)是固定的,所以这样的
z
z
z是唯一的。
所以必然只有一个点的子树不是全黑的。
那么对于路径上的另一个点
w
w
w,只要满足
d
−
d
i
s
(
w
,
z
)
=
d
1
−
d
i
s
(
x
,
z
)
d-dis(w,z)=d_1-dis(x,z)
d−dis(w,z)=d1−dis(x,z),于此同时便有
d
−
d
i
s
(
x
,
z
)
=
d
1
−
d
i
s
(
x
,
y
)
d-dis(x,z)=d_1-dis(x,y)
d−dis(x,z)=d1−dis(x,y)与
d
−
d
i
s
(
y
,
z
)
=
d
2
−
d
i
s
(
x
,
y
)
d-dis(y,z)=d_2-dis(x,y)
d−dis(y,z)=d2−dis(x,y)成立,于是我们一定可以得到相同的染色状况。
同时可以发现,这条路径上的点的
d
d
d值是呈现一个
V
V
V形的。
那么我们就可以说明所有可以得到相同树状况的点都是连通的,并且它们中
d
d
d最小的一定只有一个,同时相邻的点的
d
d
d值也是连续的。
我们不妨就在这个最小的
d
d
d上统计答案。
我们考虑一个点满足什么条件时它的
d
d
d一定是最小的。
我们先不看整棵树都是黑色的情况,那么以该点为根的最高的子树一定不是满的,而且如果我们的根不是唯一解,那么其它子树都应该是全黑的。
由于我们的
d
d
d值是呈
V
V
V形,所以除了最小值,其它点必然可以移动到一个
d
d
d值更小的点去。
显然,我们如果要让这个值更小,那么一定是向着最高的那一棵子树移动,这样我们的
d
d
d值显然是变小的。
当然,如果这个变小的
d
d
d值能够到达与原先一样的状态,那么它显然是必须将原来的其它子树都填满的。
于是原先的
d
d
d一定是得不小于次高子树的高度
+
2
+2
+2的,否则移动后就不满了。
那么如果我们当前值是最小的必要条件就有
d
⩽
h
s
e
c
+
1
d\\leqslant h_sec+1
d⩽hsec+1。
这样就可以轻松地求出总的不同情况数了。
但我们再看看原题,原题要求不是所有点都可以做根。
如果没有这个条件是很容易用连通块的
∣
V
∣
−
∣
E
∣
|V|-|E|
∣V∣−∣E∣容斥解决的,但有了这个就不能这样做了,我们不好求出根只在某个连通块中的情况数。
但实际上我们可以考虑对于原来的
d
d
d最小的点,找到一个最优秀的替代点,使其作为根时可以得到与原先相同的情况。
显然,这个替代点所在的子树必须是满的,如果在不满的子树的话,我也不可能向其移动,否则一定可以经过一个
d
d
d更小的点,那样就与我们原先的假设矛盾了。
但移动后我们肯定是有一个下限的,毕竟必须把移动到的那棵子树填满,那我们一定会选择像尽量满的子树移动,这样我们的下限会比较小,也就是涵盖所有合法的情况。
上面的方法很容易就可以用一个换根
d
p
dp
dp实现,显然是线性的。
总时间复杂度
O
(
n
)
O\\left(n\\right)
O(n)。
源码
#include<bits/stdc++.h>
using namespace std;
#define MAXN 200005
#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=924844033;
const int mod=1e5+3;
const int inv2=5e8+4;
const int jzm=2333;
const int zero=2000;
const int lim=1500;
const int M=100000;
const int orG=3,ivG=332748118;
const long double Pi=acos(-1.0);
const double eps=1e-9;
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>>=1;return t;
int n,head[MAXN],tot,mxd[MAXN],cnt[MAXN],num;LL ans;
char str[MAXN];bool key[MAXN];
struct edgeint to,nxt;e[MAXN<<1];
void addEdge(int u,int v)e[++tot]=(edge)v,head[u];head[u]=tot;
void dosaka1(int u,int fa)
mxd[u]=1;cnt[u]=key[u];
for(int i=headAtCoder AGC029E Wandering TKHS