ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【模拟赛】货病(启发式合并,分块)

2022-02-20 12:02:33  阅读:150  来源: 互联网

标签:return 分块 int mn 货病 MAXN 启发式 include define


背景

最长无笑话时间:45秒
——《Deadcodes》OI洞

题面

学校中有 n n n 个班级排成一行,每个班级都有一种独特的疫病(疫病源:OneInDark)。

接下来的 m m m 天,每一天都会发现班级 u i u_i ui​ 和班级 v i v_i vi​ 的频繁交流关系。而一整个交流圈的班级的疫病会全部共享。

同时,每天结束时 OneInDark 都会派老师巡查一段区间,若老师经过班级 i i i ,就会染上该班级共享的所有疫病。若老师染上所有疫病,OneInDark 就会很高兴。你希望最高效地让 OneInDark 高兴,所以想求出满足条件时巡查区间的最短长度。

每天都需要输出答案,每天都不独立。

输入

第一行三个整数 n , m , T n,m,T n,m,T , T T T 是强制在线系数。

接下来 m m m 行每行两个数 u ′ , v ′ u',v' u′,v′ ,其中 u i , v i u_i,v_i ui​,vi​ 定义如下:
u i = ( u ′ + T ⋅ l a s t − 1 )  ⁣ ⁣ ⁣ ⁣ m o d    n + 1 v i = ( v ′ + T ⋅ l a s t − 1 )  ⁣ ⁣ ⁣ ⁣ m o d    n + 1 u_i=(u'+T\cdot last-1)\!\!\!\!\mod n +1\\ v_i=(v'+T\cdot last-1)\!\!\!\!\mod n +1 ui​=(u′+T⋅last−1)modn+1vi​=(v′+T⋅last−1)modn+1

其中 l a s t last last 表示上一次询问的答案,特别的,第一次询问的 l a s t = 0 last=0 last=0 。

输出

共 m m m 行,每行一个答案。

数据范围

1 ≤ n ≤ 1 0 5 , 1 ≤ m ≤ 2 × 1 0 5 , 1 ≤ u ′ , v ′ ≤ n 1\leq n\leq10^5,1\leq m\leq2\times10^5,1\leq u',v'\leq n 1≤n≤105,1≤m≤2×105,1≤u′,v′≤n 。

题解

首先有个很容易想到的结论:答案单调不增。

那么我们就有个策略,每次判断答案减 1 是否可行。

假设枚举答案为 X X X,我们考虑一个极大连通块,把里面每个成员班级从小到大排个序,那么 X X X 区间能够覆盖这个连通块,当且仅当区间不在相邻两个班级之间,或者开头之前结尾之后。那么对于两个相邻的班级 a , b a,b a,b , [ a + 1 , b − X ] [a+1,b-X] [a+1,b−X] 中的班级就不能作为 X X X 区间左端点。我们把所有不能作为左端点的位置标记了,如果整个序列有位置没被标记,那么 X X X 就是可行的。

但是当 X X X 变化的时候,每个标记区间 [ a + 1 , b − X ] [a+1,b-X] [a+1,b−X] 的右端点也会变化。所以我们在每个 a + 1 a+1 a+1 处记录一个 t a g a + 1 = b − n tag_{a+1}=b-n taga+1​=b−n ,那么就可以从前往后扫描整个序列,得到是否有空位。

由于扫描整个序列是 O ( n ) O(n) O(n) 的需要优化,我们就将序列分块。当我们对连通块进行启发式合并的时候,每次修改一个点的 t a g tag tag ,就更新所在块 B B B 内每个点的信息: d i s i = i − max ⁡ { t a g j ∣ j < i , j ∈ B } , s u f i = max ⁡ { d i s j ∣ j ≥ i , j ∈ B } dis_i=i-\max\{tag_j|j<i,j\in B\},suf_i=\max\{dis_j|j\geq i,j\in B\} disi​=i−max{tagj​∣j<i,j∈B},sufi​=max{disj​∣j≥i,j∈B} 。我们最后扫描的时候,就依次访问每个块,利用先前访问的块的 t a g + ( n − X ) tag+(n-X) tag+(n−X) 最大值 r r r,查询该块的后缀 s u f r + 1 suf_{r+1} sufr+1​ 是否大于 n − X n-X n−X ,是就意味着有空位。

合理安排块大小,可以达到 O ( n log ⁡ 2 n + n n log ⁡ n ) O(n\log^2n+n\sqrt{n\log n}) O(nlog2n+nnlogn ​) 。

CODE

#include<map>
#include<set>
#include<cmath>
#include<queue>
#include<stack>
#include<random>
#include<bitset>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 100005
#define LL long long
#define ULL unsigned long long
#define ENDL putchar('\n')
#define DB long double
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define SQ 150
int xchar() {
	static const int maxn = 1000000;
	static char b[maxn];
	static int pos = 0,len = 0;
	if(pos == len) pos = 0,len = fread(b,1,maxn,stdin);
	if(pos == len) return -1;
	return b[pos ++];
}
//#define getchar() xchar()
LL read() {
	LL f = 1,x = 0;int s = getchar();
	while(s < '0' || s > '9') {if(s<0)return -1;if(s=='-')f=-f;s = getchar();}
	while(s >= '0' && s <= '9') {x = (x<<1) + (x<<3) + (s^48);s = getchar();}
	return f*x;
}
void putpos(LL x) {if(!x)return ;putpos(x/10);putchar((x%10)^48);}
void putnum(LL x) {
	if(!x) {putchar('0');return ;}
	if(x<0) putchar('-'),x = -x;
	return putpos(x);
}
void AIput(LL x,int c) {putnum(x);putchar(c);}

const int MOD = 998244353;
int n,m,s,o,k;
int Max(int a,int b) {return a>b ? a:b;}
int rd[MAXN],bl[MAXN],ll[MAXN],rr[MAXN],cn;
int sf[MAXN],sfo[MAXN];
void upd(int x) {
	int B = x/SQ+1,mx = -0x3f3f3f3f;
	for(int i = ll[B];i <= rr[B];i ++) {
		mx = Max(mx,rd[i]);
		sf[i] = sfo[i] = i - mx;
	}
	for(int i = rr[B]-1;i >= ll[B];i --) sf[i] = Max(sf[i],sf[i+1]);
	bl[B] = mx; return ;
}
set<int> a[MAXN],lm;
int fa[MAXN];
int findf(int x) {return fa[x]==x ? x:(fa[x]=findf(fa[x]));}
void unionSet(int A,int B) {
	int u = findf(A),v = findf(B);
	if(u == v) return ;
	if(a[u].size() > a[v].size()) swap(A,B),swap(u,v);
	lm.erase(*a[u].begin()); lm.erase(*a[v].begin());
	a[u].erase(n<<1|1);
	set<int> xg;
	for(auto i = a[u].begin();i != a[u].end();i ++) {
		int x = *i;
		a[v].insert(x);
		auto t = a[v].find(x),t2 = t;t2 ++;
		if(*t2 > x+1) rd[x+1] = (*t2)-n;
		else rd[x+1] = -0x3f3f3f3f;
		xg.insert(x+1);
		if(t != a[v].begin()) {
			t --;
			if(x > (*t)+1) rd[(*t)+1] = x-n;
			else rd[(*t)+1] = -0x3f3f3f3f;
			xg.insert((*t)+1);
		}
	}
	lm.insert(*a[v].begin());
	a[u].clear();
	int pr = -0x3f3f3f3f;
	for(auto i = xg.begin();i != xg.end();i ++) {
		if(*i > pr) upd(*i),pr = rr[(*i)/SQ+1];
	}
	fa[u] = v;
	return ;
}
bool check(int x) {
	int mn = *(--lm.end()) - x;
	int mr = n-x+1;
	for(int i = 1;i <= cn && ll[i] <= mr;i ++) {
		mn = Max(mn,ll[i]-1);
		int ssf = -0x3f3f3f3f;
		if(mr < rr[i]) {
			for(int j = mr;j > mn;j --) ssf = Max(ssf,sfo[j]);
		}else if(mn < rr[i]) ssf = sf[mn+1];
		if(mn < rr[i] && ssf > n-x) return 1;
		mn = Max(mn,bl[i]+(n-x));
	}
	return 0;
}
int main() {
	freopen("currency.in","r",stdin);
	freopen("currency.out","w",stdout);
	n = read(); m = read(); int op = read();
	cn = (n+1)/SQ+1;
	for(int i = 1;i <= n;i ++) {
		a[i].insert(i); fa[i] = i;
		a[i].insert(n<<1|1); lm.insert(i);
		rr[i/SQ+1] = i; rd[i] = -0x3f3f3f3f;
	}rr[(n+1)/SQ+1] = n+1;
	for(int i = n+1;i > 0;i --) ll[i/SQ+1] = i;
	for(int i = 1;i <= n;i ++) rd[i+1] = n+1;
	for(int i = 1;i <= cn;i ++) upd(ll[i]);
	int las = n;
	for(int i = 1;i <= m;i ++) {
		s = (read() + op*las - 1) % n + 1;
		o = (read() + op*las - 1) % n + 1;
		unionSet(s,o);
		while(las > 1 && check(las - 1)) las --;
		AIput(las,'\n');
	}
	return 0;
}

标签:return,分块,int,mn,货病,MAXN,启发式,include,define
来源: https://blog.csdn.net/weixin_43960414/article/details/123020232

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有