BZOJ 4320 ShangHai2006 Homework

题意:

给出N(<=1e5)个操作,操作分为两种,①在集合中添加一个数x,②问这个集合中mod x 的最小值是多少。(x <= 3e5)

题解:

0.首先我们发现log家族中有算法满足这道题目,那么采用分块的思想。

1.那么对于小于根号下MAX(x)的询问,直接暴力维护答案,对于大于根号MAX(x)的询问,只需要找到第一个大于等于K * x 的值是多少。

2.那么现在问题是维护第一个大于等于K * x 的值是多少,现在有两种选择,①用STL中的<set> 中的 lower_bound 复杂度为logx  ②用并查集充当链表 复杂度很小

代码:

#include <iostream>
#include <cstring>
#include <cstdio>
using namespace std;

const int block = 507;
const int N = 3e5 + 7;
char ch[2];
int pa[N], x, q[N], o[N], ans[N], mini[N], n, cnt;

int find (int x) {
	return pa[x] == x ? x : pa[x] = find (pa[x]);
}

int main () {
	scanf ("%d", &n);
	memset (mini, 127, sizeof mini);
	for (int i = 0; i < N; ++i) pa[i] = i + 1;
	for (int i = 1; i <= n; ++i) {
		scanf ("%s%d", ch, &x);
		if (ch[0] == ‘A‘) {
			o[i] = 1;
			q[i] = x;
			pa[x] = x;
			for (int i = 1; i <= block; ++i) {
				mini[i] = min (mini[i], x % i);
			}
		}
		else if (ch[0] == ‘B‘) {
			o[i] = 2;
			q[i] = x;
			if (q[i] <= block) ans[i] = mini[q[i]];
		}
	}
	for(int i = N - 1;i >= 0; --i) pa[i] = find(pa[i]);
	for (int i = n; i >= 1; --i) {
		if (o[i] == 1) pa[find (q[i])] = pa[find (q[i] + 1)];
		else if (o[i] == 2) {
			if (q[i] > block) {
				int ret = 1e9+7;
				for (int j = 0; j < N; j += q[i]) {
					if (find (j) == N) continue;
					ret = min (ret, find(j) % q[i]);
				}
				ans[i] = ret;
				if (ret == 1e9+7) ans[i] = q[i] - 1;
			}
		}
	}
	for (int i = 1; i <= n; ++i) if (o[i] == 2) printf ("%d\n", ans[i]);
	return 0;
}

  

总结:

合理运用并查集当链表的性质QAQ

时间: 2025-01-01 05:52:00

BZOJ 4320 ShangHai2006 Homework的相关文章

bzoj 4320: ShangHai2006 Homework【分块】

按根号300000=m分情况讨论 查询是,当x小于等于m,那么可以暴力记录直接出解:否则,用分块维护区间值,查询的时候以x为步长跳根号m次取最小值即可 还有一种并查集方法,来自https://www.cnblogs.com/CQzhangyu/p/7088337.html #include<iostream> #include<cstdio> using namespace std; const int N=300010,M=550; int n=300000,m=n/M,q,i,

4320: ShangHai2006 Homework

4320: ShangHai2006 Homework 链接 分析: 分块.对权值模数进行分块,模数小于$\sqrt V$的($V$为权值上界),暴力处理. 模数大于$\sqrt V$的,设模数是k,枚举k的倍数,然后查询大于[k,2k]之间的最小的数x,这个区间的mod k最小的数就是x-k.k的倍数共有$\sqrt V$个,每次查询,再对权值进行分块,并维护后缀最小值,做到$O(1)$查询.复杂度$O(n \sqrt V)$ 代码: #include<cstdio> #include<

【BZOJ4320】ShangHai2006 Homework 分段+并查集

[BZOJ4320]ShangHai2006 Homework Description 1:在人物集合 S 中加入一个新的程序员,其代号为 X,保证 X 在当前集合中不存在. 2:在当前的人物集合中询问程序员的mod Y 最小的值. (为什么统计这个?因为拯救过世界的人太多了,只能取模) Input 第一行为用空格隔开的一个个正整数 N. 接下来有 N 行,若该行第一个字符为“A” ,则表示操作 1:若为“B”,表示操作 2: 其中 对于 100%的数据:N≤100000, 1≤X,Y≤3000

BZOJ 4320 Homework

首先要想清楚一定是按根号分块.对于<根号的直接记录.>根号的怎么办呢? 设查询的是%y. 那么我们只要找一个0,y,2y,3y.....的lowerbound就好了.而这是根号的.到此总复杂度n√nlogn,无法通过此题. 怎么办呢?可以考虑离线.我们维护并查集,每个点的祖先是在数轴上它的右边第一个出现的数. 那么倒着做就是删数,就可以合并两个集合,就好了.复杂度n√nα(n). #include<iostream> #include<cstdio> #include&

BZOJ4320 ShangHai2006 Homework

Description 1:在人物集合 S 中加入一个新的程序员,其代号为 X,保证 X 在当前集合中不存在. 2:在当前的人物集合中询问程序员的mod Y 最小的值. (为什么统计这个?因为拯救 过世界的人太多了,只能取模) Input 第一行为用空格隔开的一个个正整数 N. 接下来有 N 行,若该行第一个字符为“A” ,则表示操作 1:若为“B”,表示操作 2: 其中 对于 100%的数据:N≤100000, 1≤X,Y≤300000,保证第二行为操作 1. Output 对于操作 2,每行

【bzoj4320】ShangHai2006 Homework

若Y小于等于sqrt(300000),暴力,对所有的插入的数都更新mn[i]. 若Y大于sqrt(300000),枚举kY,用并查集维护>=i的第一个数,这样只支持删除操作是O(1),然后倒着枚举一边,删除一个数x那么就fa[x]=fa[x+1] #include<algorithm> #include<iostream> #include<cstdlib> #include<cstring> #include<cstdio> #inclu

论逗逼的自我修养——乱做计划

我看IOI各种鬼畜题目做做,深知自身姿势水平不足无以抗衡就乱搞一些傻逼题做做. 现在已经跪了0道 [BZOJ3749][POI2015]?asuchy 枚举第一个狗粮被谁吃了,后面的dp就可以了,记录下dp的路径,最后时候验证与假设是否矛盾即可. [BZOJ3750][POI2015]Piecz?? 暴力枚举左上角判断一下. [BZOJ3733][Pa2013]lloczyn 一开始用一个诡异的姿势WA了之后很久没能想出多项式做法,膜了一发鏼之后发现是大(d)法(f)师(s).我们从小到大枚举不

待 题表

题表 达哥终极杂题表Bzoj2839 hdu6021 Codeforces 804DBzoj2248 hdu5575 Codeforces 786CBzoj2013 bzoj2676 Codeforces 803CBzoj2386 bzoj3782 Codeforces 813DBzoj2699 cogs1667 Codeforces 814DBzoj4798 bzoj2064 Codeforces 814EBzoj4639 bzoj3505 Codeforces 815ABzoj4417 bz

BZOJ 3379: [Usaco2004 Open]Turning in Homework 交作业

Description 贝茜有C(1≤C≤1000)门科目的作业要上交,之后她要去坐巴士和奶牛同学回家. 每门科目的老师所在的教室排列在一条长为H(1≤H≤1000)的走廊上,他们只在课后接收作业.交作业不需要时间.贝茜现在在位置0,她会告诉你每个教室所在的位置,以及走廊出口的位置.她每走1个单位的路程,就要用1秒.她希望你计算最快多久以后她能交完作业并到达出口. Input 第1行输入三个整数C,H,B,B是出口的位置.之后C行每行输入两个整数,分别表示一个老师所在的教室和他的下课时间. Ou