Examples

P8375 [APIO2022] 游戏 解题报告

P8375 [APIO2022] 游戏 解题报告:

更好的阅读体验

题意

你要维护 n 个点的一张图,令编号在 [1,k] 的点为关键点,需要支持加边,以及在线维护是否存在含有关键点的环。

1n3×105,1m5×105

分析

挺好的题。

动态维护是否成环这个问题是不太可做的,于是我们需要关注题目中关键点形成的一条链。

很容易想到对于每个点维护 Lx,Rx 表示能到达它的最大关键点与它能到达的最小关键点,那么存在要求的环当且仅当存在一个点满足 LxRx

每次修改的时候暴力 check 是否能更新 L,R 即可做到 O((n+m)k)。(势能分析,一次更新 L,R 至少靠近一格)

接着观察性质,可以发现若 xy,那么 LxLy,RxRy,进一步可以发现关于 p 的修改若让其他点不合法了(即存在 q 使得 LqRq),p 一定也会不合法。于是我们只需要维护每个点的 L,R,而不需要检查每个点的 L,R 是否合法。

于是有了一个简单的想法,对序列分块,当一个点的左右端点不在一个块时一个个块跳,否则一个个点跳,这样的复杂度就是 O((n+m)k) 了。

可以发现这道题利用到的分块性质,套在线段树上都可以满足,我们将分块换成线段树,维护每个点对应区间在线段树上被包含的极小结点并暴力向下跳,即可做到 O((n+m)logk)

代码

出乎意料的好写。

#include<stdio.h>
#include<vector>
using namespace std;
void init(int n, int k);
int add_teleporter(int u, int v);
const int maxn=300005;
int flg;
int L[maxn],R[maxn]; 
vector<int>v[maxn],w[maxn];
void init(int n,int k){
	flg=0;
	for(int i=1;i<=n;i++){
		if(i<=k)
			L[i]=R[i]=i;
		else L[i]=0,R[i]=k+1;
		v[i].clear(),w[i].clear();
	}
}
void check(int x,int y);
void inspect(int x){
	for(int i=0;i<v[x].size();i++)
		check(x,v[x][i]);
	for(int i=0;i<w[x].size();i++)
		check(w[x][i],x);
}
void check(int x,int y){
	if(L[x]>=R[y]){
		flg=1;
		return ;
	}
	int Mx=(L[x]+R[x])>>1,My=(L[y]+R[y])>>1;
	if(L[x]>=My+1)
		L[y]=My+1,inspect(y);
	if(R[y]<=Mx)
		R[x]=Mx,inspect(x);
}
int add_teleporter(int x,int y){
	x++,y++,v[x].push_back(y),w[y].push_back(x),check(x,y);
	return flg;
}
posted @   xiaoziyao  阅读(154)  评论(1编辑  收藏  举报
相关博文:
阅读排行:
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· ollama系列01:轻松3步本地部署deepseek,普通电脑可用
· 25岁的心里话
· 按钮权限的设计及实现
点击右上角即可分享
微信分享提示