[ACNOI2021]《普林斯普的余威》

题目

题目背景
O n e I n D a r k \sf OneInDark OneInDark 站在 O U Y E \sf OUYE OUYE 的面前,接受神的洗礼。汝必先弃置肉身,方可入众神之门。 话音刚落, O n e I n D a r k \sf OneInDark OneInDark 感觉自己开始慢慢缩成一团,越缩越紧,最后以一个诡异而扭曲的姿势瘫倒在地。他的呼吸变得缓慢,目光变得柔和。这是一个凄美的结尾。

许多年后,考古学家发掘出了 O n e I n D a r k \sf OneInDark OneInDark 的遗体化石。他们无不惊讶地发现, O n e I n D a r k \sf OneInDark OneInDark 的每一根骨头都是弯曲的!这也是人类历史上第一个,被别人 卷死 的案例。

在同一地点,人们还发现了遗迹化石,上面赫然写着一句话:吾之魂需一肉身,正如植物需要泥土。吾之头脑好似玻璃,记忆好似光。

题目描述
给出一个树,求有多少个点对 x , y    ( x < y ) x,y\;(x<y) x,y(x<y) 满足:树上 x , y x,y x,y 两点的唯一简单路径中,经过的所有点的编号都在 [ x , y ] [x,y] [x,y] 内。

数据范围与提示
n ⩽ 2 × 1 0 6 n\leqslant 2\times 10^6 n2×106 。但是显然不是线性的。

思路

第一步,膜拜 O U Y E \sf OUYE OUYE,轻易地做出了牺牲者 O n e I n D a r k \sf OneInDark OneInDark 做不出的题。当众人努力扛起补题的重担时, O U Y E \sf OUYE OUYE 正哼着小曲,做着自己一眼就看得出来的 N O I \rm NOI NOI 题目。卷爷 O U Y E \sf OUYE OUYE 是问题转化之神!

那么题目背景试图告诉我们什么呢?弃置原有的肉身 抛开原有的树形结构。原有的树形结构实在是一个可恶的误导信息:一旦想到点分治,或者一切跟树上路径有关的东西,你就必死无疑。

问题显然等价于,求有多少条路径满足路径上经过的点的编号 min ⁡ , max ⁡ \min,\max min,max 在端点处取得。有一个非常恐怖但是完全正确的想法是,不去求出路径。单纯考虑求出路径 min ⁡ \min min 。这比较类似于求出路径上边权的 min ⁡ \min min 值,可以用最小生成树;所以求点权的 min ⁡ \min min 其实也是类 克鲁斯卡尔重构树

而最值在端点处,等价于删掉端点(删掉最值点)后路径不断开。放在重构树上去理解,就是一条路径的最值点不能在路径中间。而路径的最值点就是 l c a lca lca,如果要 l c a lca lca 在路径的端点,其实就是 x x x y y y 的祖先。竟然会转化出这么简洁的关系式,难以想象!

现在我们建出两棵重构树 T 1 , T 2 T_1,T_2 T1,T2,问多少个点对 ( x , y ) (x,y) (x,y) 满足 T 1 T_1 T1 x x x y y y 的祖先, T 2 T_2 T2 y y y x x x 的祖先。在 T 2 T_2 T2 d f s \rm dfs dfs 即可取出所有 T 2 T_2 T2 x x x 的祖先 y y y,需要快速求出 T 1 T_1 T1 中哪些 y y y 可以在 x x x 子树内。显然求出 d f s \rm dfs dfs 序后用芬威克树即可维护, O ( n log ⁡ n ) \mathcal O(n\log n) O(nlogn) 且常数很小,代码实现极为简单。

代码

#include <cstdio> // XJX yyds!!!
#include <iostream>
#include <vector>
#include <cstring>
#include <algorithm>
#include <cctype>
using namespace std;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
typedef long long llong;
inline int readint(){
    
    
	int a = 0, c = getchar(), f = 1;
	for(; !isdigit(c); c=getchar())
		if(c == '-') f = -f;
	for(; isdigit(c); c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
void writeint(int x){
    
    
	if(x > 9) writeint(x/10);
	putchar(char((x%10)^48));
}

const int MAXN = 6000006;
struct Edge{
    
    
	int to, nxt;
	Edge() = default;
	Edge(int _to,int _nxt):
		to(_to),nxt(_nxt){
    
     }
};
Edge e[MAXN<<1];
int head[MAXN], cntEdge;
void addEdge(int a,int b){
    
    
	e[cntEdge] = Edge(b,head[a]);
	head[a] = cntEdge ++;
}

namespace UFS{
    
    
	int fa[MAXN];
	void init(int n){
    
    
		rep(i,1,n) fa[i] = i;
	}
	int find(int a){
    
    
		return (fa[a] != a) ? (fa[a] = find(fa[a])) : a;
	}
	void merge(int a,int b){
    
    
		fa[find(a)] = find(b);
	}
}

int st[MAXN], ed[MAXN], dfsClock;
void scan(int x,const int &n){
    
    
	st[x-n] = ++ dfsClock;
	for(int i=head[x]; ~i; i=e[i].nxt)
		scan(e[i].to,n);
	ed[x-n] = dfsClock;
}

int c[MAXN]; llong ans;
void dfs(int x,const int &n){
    
    
	for(int i=ed[x-2*n]; i; i&=(i-1)) ans += c[i];
	for(int i=st[x-2*n]-1; i; i&=(i-1)) ans -= c[i];
	for(int i=st[x-2*n]; i<=n; i+=(i&-i)) ++ c[i];
	for(int i=head[x]; ~i; i=e[i].nxt) dfs(e[i].to,n);
	for(int i=st[x-2*n]; i<=n; i+=(i&-i)) -- c[i];
}

int main(){
    
    
	int n = readint();
	memset(head+1,-1,(3*n)<<2);
	readint(); // fa(1) = 0
	for(int i=2,f; i<=n; ++i){
    
    
		f = readint();
		addEdge(i,f), addEdge(f,i);
	}
	
	UFS::init(n);
	rep(i,1,n) for(int j=head[i]; ~j; j=e[j].nxt){
    
    
		int p = UFS::find(e[j].to);
		if(e[j].to < i && p != UFS::find(i))
			addEdge(i+n,p+n), UFS::merge(p,i);
	}
	
	UFS::init(n);
	drep(i,n,1) for(int j=head[i]; ~j; j=e[j].nxt){
    
    
		int p = UFS::find(e[j].to);
		if(e[j].to > i && p != UFS::find(i))
			addEdge(i+n*2,p+2*n), UFS::merge(p,i);
	}
	
	scan(n<<1,n), dfs(n<<1|1,n);
	printf("%lld\n",ans);
	return 0;
}

后记

又过了很多年,人们才知道, O n e I n D a r k \sf OneInDark OneInDark 只是 O U Y E \sf OUYE OUYE 转生的牺牲品。 O U Y E \sf OUYE OUYE 究竟内卷多久了?没有人知道。从人类有文字记载的历史开始, O U Y E \sf OUYE OUYE 就一直在卷,并且将一直卷到今天,卷到明天,卷到人类文明不复存在。凭借转生之术, O U Y E \sf OUYE OUYE 必将永世长存!

为何转生需要牺牲品呢?因为: When you take another’s life, you take your own. \text{When you take another's life, you take your own.} When you take another’s life, you take your own.

猜你喜欢

转载自blog.csdn.net/qq_42101694/article/details/121257527