[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) d1dis(x,z)=d2dis(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) ddis(w,z)=d1dis(x,z),于此同时便有 d − d i s ( x , z ) = d 1 − d i s ( x , y ) d-dis(x,z)=d_1-dis(x,y) ddis(x,z)=d1dis(x,y) d − d i s ( y , z ) = d 2 − d i s ( x , y ) d-dis(y,z)=d_2-dis(x,y) ddis(y,z)=d2dis(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 dhsec+1
这样就可以轻松地求出总的不同情况数了。

但我们再看看原题,原题要求不是所有点都可以做根。
如果没有这个条件是很容易用连通块的 ∣ V ∣ − ∣ E ∣ |V|-|E| VE容斥解决的,但有了这个就不能这样做了,我们不好求出根只在某个连通块中的情况数。
但实际上我们可以考虑对于原来的 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

AGC017D Game on Tree(树型博弈)

AGC018F. Two Trees

树形dp/启发式合并Atcoder1272/AGC007E

[AGC017D]Game on Tree

AGC004D Teleporter