[CSP-S模拟测试]:飘雪圣域(莫队)

题目描述

  $IcePrincess\text{_}1968$和$IcePrince\text{_}1968$长大了,他们开始协助国王$IceKing\text{_}1968$管理国内事物。
  $IcePrincess\text{_}1968$和$IcePrince\text{_}1968$住在一个宁静悠远的王国:$IceKingdom$——飘雪圣域。飘雪圣域有$n$个城镇,编号$1,2,3...n$。有些城镇之间有道路,且满足任意两点之间有且仅有一条路径。飘雪圣域风景优美,但气候并不是太好。根据$IcePrince\text{_}1968$的气候探测仪,将来会发生$q$场暴风雪。每场暴风雪可以用两个整数$l_i,r_i$刻画,表示这场暴风雪之后,只有编号属于$[l_i,r_i]$的城市没有受到暴风雪的影响。
  在暴风雪的影响下迅速确定王国的农业生产方案是非常重要的事情。$IceKing\text{_}1968$认为,一个农业生产地域应该是一个极大连通块,满足每个节点都没有被暴风雪影响。这里极大连通块的定义是:不存在一个不属于该点集的未被暴风雪影响的点与该连通块连通。
  $IcePrincess\text{_}1968$要负责算出每次暴风雪后,王国能拥有多少个农业生产地域。注意这里每次暴风雪是独立的,即每次暴风雪过后,直到每个城镇重新焕发生机,下一次暴风雪才会到来。
  正如上文所述,$IcePrincess\text{_}1968$擅长文学但不擅长计算机,于是请你帮忙。


输入格式

  输入文件名为$icekingdom.in$。
  第一行包含两个正整数$n,q$,表示$IceKingdom$的城镇个数和暴风雪次数。
  第$2$至第$n$行,每行两个正整数$x,y$,表示城镇$x$和城镇$y$之间有一条道路。
  第$n+1$至第$n+q$行,每行两个正整数$l_i,r_i$,描述一场暴风雪,含义如题面所述。


输出格式

  输出文件名$icekingdom.out$。
  输出文件共有$q$行,第$i$行表示在第$i$场暴风雪之后农业生产地域的个数。


样例

样例输入:

4 3
1 2
2 3
2 4
1 2
1 3
3 4

样例输出:

1
1
2


数据范围与提示

样例解释:

第一次询问,只有$(1,2)$一个连通块。
第二次询问,只有$(1,2,3)$一个连通块。
第三次询问,有$3$和$4$两个连通块。

数据范围:

对于$30\%$的数据:$n\leqslant 100,q\leqslant 100$;
对于$50\%$的数据:$n\leqslant 2,000,q\leqslant 2,000$;
对于$100\%$的数据:$n\leqslant 200,000,q\leqslant 200,000$,对于所有的暴风雪,$l_i\leqslant r_i$。


题解

官方正解中的两种做法都是用的数据结构,然而我用的是莫队……

加一个点它对答案的贡献是$1-$与它连接的没有受到暴风雪影响的点,$1$是因为它自己可以作为一个新的联通块,减去没有收到暴风雪影响的点是因为它会合并这些联通块;删点同理。

显然$200,000$的数据范围莫队一定要有$\Theta(1)$修改的方法。

不妨以加的操作为例,为做到$\Theta(1)$修改,就需要找到方法快速求出与它连接的没有受到暴风雪影响的点。

先预处理出来所有点的父亲,并设$num[x]$为点$x$的儿子中没有受到暴风雪影响的点的个数,加入一个点的同时将它父亲的$num+1$即可,注意统计答案时不要忘了父亲。

删点同理。

时间复杂度:$\Theta(n\sqrt{n})$。

期望得分:$100$分。

实际得分:$100$分。


代码时刻

#include<bits/stdc++.h>
using namespace std;
struct node{int nxt,to;}e[500000];
struct rec{int l,r,pos,id;}q[200001];
int head[200001],cnt;
int n,m;
int ans[200001],l,r,now;
int num[200001],fa[200001];
bool vis[200001];
void add(int x,int y)
{
	e[++cnt].nxt=head[x];
	e[cnt].to=y;
	head[x]=cnt;
}
bool cmp(rec a,rec b){return (a.pos)^(b.pos)?a.l<b.l:(((a.pos)&1)?a.r<b.r:a.r>b.r);}
void add(int x)
{
	vis[x]=1;
	now++;
	now-=num[x];
	num[fa[x]]++;
	if(vis[fa[x]])now--;
}
void del(int x)
{
	vis[x]=0;
	now--;
	now+=num[x];
	num[fa[x]]--;
	if(vis[fa[x]])now++;
}
void dfs(int x)
{
	for(int i=head[x];i;i=e[i].nxt)
		if(!fa[e[i].to]&&e[i].to>1){fa[e[i].to]=x;dfs(e[i].to);}
}
int main()
{
	scanf("%d%d",&n,&m);
	int t=sqrt(n);
	for(int i=1;i<n;i++)
	{
		int x,y;
		scanf("%d%d",&x,&y);
		add(x,y);add(y,x);
	}
	dfs(1);
	for(int i=1;i<=m;i++)
	{
		scanf("%d%d",&q[i].l,&q[i].r);
		q[i].pos=(q[i].l-1)/t+1;
		q[i].id=i;
	}
	sort(q+1,q+m+1,cmp);
	l=r=1;add(1);
	for(int i=1;i<=m;i++)
	{
		while(l>q[i].l)add(--l);
		while(r<q[i].r)add(++r);
		while(l<q[i].l)del(l++);
		while(r>q[i].r)del(r--);
		ans[q[i].id]=now;
	}
	for(int i=1;i<=m;i++)printf("%d\n",ans[i]);
	return 0;
}


rp++

原文地址:https://www.cnblogs.com/wzc521/p/11678796.html

时间: 2024-10-08 02:48:09

[CSP-S模拟测试]:飘雪圣域(莫队)的相关文章

csp-s模拟测试50(9.22)「施工(单调栈优化DP)」&#183;「蔬菜(二维莫队???)」&#183;「联盟(树上直径)」

改了两天,终于将T1,T3毒瘤题改完了... T1 施工(单调栈优化DP) 考场上只想到了n*hmaxn*hmaxn的DP,用线段树优化一下变成n*hmaxn*log但显然不是正解 正解是很**的单调栈 可以想象到最优情况一定是将两端高于中间的一段平原填成一段平的坑,不然如果坑内存在高度差那么我们即使只将一部分抬升也肯定没有用处,并且如果中间的坑已经高于了两端,再向上升也肯定不优,然后就中间的坑可以很很小,也可以很长,对于这个模型我们首先想到n^2*h的DP 设当前表示的f[i]表示当前到了i节

[CSP-S模拟测试]:sum(数学+莫队)

题目传送门(内部题63) 输入格式 第一行有一个整数$id$,表示测试点编号.第一行有一个整数$q$,表示询问组数.然后有$q$行,每行有两个整数$n_i,m_i$. 输出格式 一共有$q$行,每行一个整数表示每组询问的答案$S_{n_i,m_i}$对$10^9+7$取模的结果. 样例 样例输入: 151 12 13 24 35 5 样例输出: 2371532 数据范围与提示 对于所有数据,$1\leqslant q,n_i,m_i\leqslant 10^5$. 题解 考场上把$80$分部分分

[CSP-S模拟测试]:ants(回滚莫队)

题目描述 然而贪玩的$dirty$又开始了他的第三个游戏. $dirty$抓来了$n$只蚂蚁,并且赋予每只蚂蚁不同的编号,编号从$1$到$n$.最开始,它们按某个顺序排成一列.现在$dirty$想要进行$m$场比赛,每场比赛给出$l$和$r$,表示选出从左向右数第$l$只至第$r$只蚂蚁.被选出的蚂蚁需要快速地按编号从小到大排序,之后这些蚂蚁中编号连续的蚂蚁将围成一个圈.每场比赛结束后,蚂蚁们还需要快速地回到最开始的位置. 按照蚂蚁的审美标准,围成的圈越大美观值就越大.于是$dirty$每次需要

【10.22校内测试】【二分】【二分图】【很像莫队的乱搞/树状数组】

Solution 谁能想到这道题卡读入??还卡了70pts??? 二分+$n^2$check就行了 Code #include<bits/stdc++.h> using namespace std; int n, m; int sum[2005][2005]; void read(int &x) { x = 0; char ch = getchar(); while(ch > '9' || ch < '0') ch = getchar(); while(ch >= '

[知识点]莫队大法好

昨天的模拟赛T3是个非常恶心的东东,不过今天获知有人莫队+O3卡常A了== 但是原来OD表示莫队目前没什么用不用学,就没学过,所以昨天无奈不会打 但是今天哼哼,学会了这个新的知识点,而且觉得还是挺好用的啊 毕竟暴力是哪里都能用得上的... 所谓莫队,是一个优雅的暴力 解决的问题就是离线区间询问,好像是无敌的.(然而区间修改我目前还不会,而且区间最值好像也不会,而且区间最值也不用莫队233) 首先我们知道区间[L,R],那么我们一定能暴力求出来[L‘,R'].我们将所有询问存起来,暴力求出来第一个

莫队算法~讲解

用了大约1h搞定了基础的莫队算法.写篇博客算是检验下自己的学习成果. 一.什么是莫队算法? 莫队算法是用来处理一类无修改的离线区间询问问题.——(摘自前国家队队长莫涛在知乎上对莫队算法的解释.) 莫队算法是前国家队队长莫涛在比赛的时候想出来的算法. 传说中能解决一切区间处理问题的莫队算法. 准确的说,是离线区间问题.但是现在的莫队被拓展到了有树上莫队,带修莫队(即带修改的莫队).这里只先讲普通的莫队. 还有一点,重要的事情说三遍!莫队不是提莫队长!莫队不是提莫队长!!莫队不是提莫队长!!! 二.

初探莫队

2019年的某月某天某神仙讲了莫队,但是我一直咕咕咕到了2020年 什么是莫队 莫队是一种优雅的暴力,也是用来完成区间询问的.普通莫队复杂度\(O(n \sqrt n)\).一种十分优美的离线做法 前置芝士 0.拥有脑子 1.\(STL\)中\(sort\)的\(cmp\) 2.看/写超长的三目运算符的耐心 3.分块的思想 当然了如果不会这些也没有关系,下面还会再讲的 正片开始 先来一道卡了莫队的莫队模板题 HH的项链 最最暴力的做法:显然我们可以对每个询问暴力跑一次,但显然\(O(n^2)\)

(莫队算法)CodeForces - 617E XOR and Favorite Number

题意: 长度为n的数列,m次询问,还有一个k.每次询问询问询问从数列的L到R内有多少个连续子序列异或起来等于k. 分析: 因为事先知道这题可以用莫队写,就正好用这题练习莫队. 预处理每个前缀异或和. 然后莫队按分块排序后,不断更新,用一个数组cnt[]记录当前L到R前缀和的数量. R向右拉,新增的数量就是cnt[pre^k],pre表示当前这个R位置的前缀异或和,然后更新一下cnt. 其他的也类似. 算是一个比较好的入门题. 代码: 1 #include <cstdio> 2 #include

莫队算法

Beautiful Girl 题意 给定一个长度为 n 的序列 a[1], a[2], ..., a[n] . m 组询问 (l, r, K) , 求区间 [l, r] 去除重复的数之后的第 K 小. n, m <= 100000 . 分析 莫队算法 + 值域分块. 1 #include <cstdio> 2 #include <cstring> 3 #include <cstdlib> 4 #include <cctype> 5 #include &