首页 > 其他分享 >P4168 [Violet] 蒲公英 (莫队的强制在线)

P4168 [Violet] 蒲公英 (莫队的强制在线)

时间:2024-04-22 22:33:55浏览次数:25  
标签:le int 莫队 Violet 区间 蒲公英 col P4168

前言

当个乐子看就行
所用时间不如分块正解快
虽然在线莫队实质也是分块

[Violet] 蒲公英

题目背景

亲爱的哥哥:

你在那个城市里面过得好吗?

我在家里面最近很开心呢。昨天晚上奶奶给我讲了那个叫「绝望」的大坏蛋的故事的说!它把人们的房子和田地搞坏,还有好多小朋友也被它杀掉了。我觉得把那么可怕的怪物召唤出来的那个坏蛋也很坏呢。不过奶奶说他是很难受的时候才做出这样的事的……

最近村子里长出了一大片一大片的蒲公英。一刮风,这些蒲公英就能飘到好远的地方了呢。我觉得要是它们能飘到那个城市里面,让哥哥看看就好了呢!

哥哥你要快点回来哦!

爱你的妹妹 Violet

Azure 读完这封信之后微笑了一下。

“蒲公英吗……”

题目描述

在乡下的小路旁种着许多蒲公英,而我们的问题正是与这些蒲公英有关。

为了简化起见,我们把所有的蒲公英看成一个长度为 \(n\) 的序列 \(\{a_1,a_2..a_n\}\),其中 \(a_i\) 为一个正整数,表示第 \(i\) 棵蒲公英的种类编号。

而每次询问一个区间 \([l, r]\),你需要回答区间里出现次数最多的是哪种蒲公英,如果有若干种蒲公英出现次数相同,则输出种类编号最小的那个。

注意,你的算法必须是在线的

输入格式

第一行有两个整数,分别表示蒲公英的数量 \(n\) 和询问次数 \(m\)。

第二行有 \(n\) 个整数,第 \(i\) 个整数表示第 \(i\) 棵蒲公英的种类 \(a_i\)。

接下来 \(m\) 行,每行两个整数 \(l_0, r_0\),表示一次询问。输入是加密的,解密方法如下:

令上次询问的结果为 \(x\)(如果这是第一次询问,则 \(x = 0\)),设 \(l=((l_0+x-1)\bmod n) + 1,r=((r_0+x-1) \bmod n) + 1\)。如果 \(l > r\),则交换 \(l, r\)。
最终的询问区间为计算后的 \([l, r]\)。

输出格式

对于每次询问,输出一行一个整数表示答案。

样例 #1

样例输入 #1

6 3 
1 2 3 2 1 2 
1 5 
3 6 
1 5

样例输出 #1

1 
2 
1

提示

数据规模与约定

  • 对于 \(20\%\) 的数据,保证 \(n,m \le 3000\)。
  • 对于 \(100\%\) 的数据,保证 \(1\le n \le 40000\),\(1\le m \le 50000\),\(1\le a_i \le 10^9\),\(1 \leq l_0, r_0 \leq n\)。

分析

我跟正常人不一样系列

颓的时候偶然看见一种神奇的莫队

\[\color{#40c0bb}\large \textbf {莫队的强制在线} \]

知周所众 莫队是一种离线算法

而诗乃神犇将莫队进行了在线化改造  %%%诗乃

于是乎 我们就可以用在线莫队来解决这个问题啦~

根据诗乃大佬的理论

由于普通莫队是将所有询问离线排好序,然后每一次从上一个询问区间转移过来的

而想要莫队在线,我们需要预先处理好某些区间的答案,让这些区间成为莫队中的“上一个区间”,这些区间我们称为特征区间

根据诗乃大佬的证明 区间长度\(d=\sqrt{n}\)为最佳区间长度

对于特征区间需要维护的信息主要包括

1. 区间答案

2. 莫队所需要的信息(如区间中每种颜色的出现次数)

对于本题,我们设下许多特征区间,在这里的处理与分块的做法相同,不再赘述

一个区间(设其为\(L\sim R\))的众数只能是它中间夹的一堆些连续特征区间(设其为\(l\sim r\))整个的众数 \(or\) \(L\sim l\)的蒲公英的各种种类 \(or\) \(r\sim R\)的蒲公英的各种种类

所以我们不仅要预处理每个特征区间出现的种类的个数,还要处理\(i\sim j\)的众数

然后在询问时将\(l\),\(r\)(定义见上)分别移到\(L\),\(R\)即可。

由于是在线莫队,每次要清空\(cnt\)数组,需要再跳回来

记得还要将众数的出现次数清空

code

Elaina's code
#include<bits/stdc++.h>
using namespace std;
const int N=100000;
const double eps=1e-8;
#define ll long long
//#define int long long
#define inf 0x3f
#define INF 0x3f3f3f3f
#define mst(a,b) memset(a,b,sizeof(a))
#define re register
#define Elaina 0
inline int read(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}

int target[N];
int nc,n,m,l=1,r=0,ans,maxx=0,num=0,col[N],a[N],anss[500][500],lsh[N];
//anss[i][j]为编号为i的特征区间到编号为j的特征区间的众数

bool vis[N];
int size,s_block;

int L[N],R[N],CNT[500][N],belong[N],cnt=0;
//CNT[i][j]表示第i个块中j种蒲公英的个数 
 
int mp[N];
map<int,int> mpp;
struct node{
	int x,y,id;
}q[N];

inline int find(int x){
	int l=0,r=n+1;
	while(l+1<r){
		int mid=(l+r)>>1;
		if(lsh[mid]<x)l=mid;
		else r=mid;
	}
	return r;
}

void init(){
	s_block=size=sqrt(n);
	for(int i=1;i<=s_block;i++){//预处理 
		L[i]=(i-1)*size+1,R[i]=i*size;
		for(int j=L[i];j<=R[i];j++){
			CNT[i][a[j]]++;
			belong[j]=i;
		}
		for(int j=1;j<=cnt;j++){//特征区间一般存前缀和 
			CNT[i][j]+=CNT[i-1][j];
		}
	}
	if(size*size<n){//若有剩余 
		s_block++;
		L[s_block]=size*size+1,R[s_block]=n;
		for(int i=size*size+1;i<=n;i++){
			CNT[s_block][a[i]]++;
			belong[i]=s_block;
		}
		for(int i=1;i<=cnt;i++){
			CNT[s_block][i]+=CNT[s_block-1][i];
		}
	}
	for(int i=1;i<=s_block;i++){//anss处理
		for(int j=i;j<=s_block;j++,anss[i][j]=anss[i][j-1]){
			for(int k=L[j];k<=R[j];k++){
				col[a[k]]++;
				if(col[a[k]]>col[anss[i][j]])anss[i][j]=a[k];
				else if(col[a[k]]==col[anss[i][j]]&&a[k]<anss[i][j])anss[i][j]=a[k];
			}
		}
		for(int j=1;j<=cnt;j++)col[j]=0;
	}
}

void add(int l,int r,int x,int k){
	if(!col[x]){//如第一次出现该种颜色,那就要加上l~r中x出现的次数
		col[x]=CNT[r][x]-CNT[l-1][x];
		vis[x]=1;
	}else if(k<0&&vis[x]){//返回时第一次出现该种颜色,就要减去l~r中x出现的次数
		col[x]-=CNT[r][x]-CNT[l-1][x];
		vis[x]=0;
	}
	col[x]+=k;
	if(k<0){
		return;
	}
	if(col[x]>col[ans]){
		ans=x;
	}else if(col[x]==col[ans]&&x<ans){
		ans=x;
	}
}
main(){
	n=read(),m=read();
	for(int i=1;i<=n;i++)lsh[i]=a[i]=read();
	sort(lsh+1,lsh+1+n);
	for(int i=2;i<=n;i++)
		if(lsh[i-1]==lsh[i])lsh[i-1]=1e9+10;
	sort(lsh+1,lsh+1+n);
	for(int i=1;i<=n;i++){//离散化
		int wz=find(a[i]);
		mp[wz]=a[i],a[i]=wz;
		cnt=max(cnt,a[i]);
	}
	
	init();
	for(int i=1;i<=m;i++){
		int Li=(read()+mp[ans]-1)%n+1,Ri=(read()+mp[ans]-1)%n+1;
		if(Li>Ri)swap(Li,Ri);
		int LL=Ri+1,RR=Ri;
		int l=Ri+1,r=Ri,posl=1,posr=0;
		if(belong[Li]+1<belong[Ri]){//中间有特征区间
			posl=belong[Li]+1,posr=belong[Ri]-1;
			ans=anss[posl][posr];
			l=LL=L[posl];
			r=RR=R[posr];
			col[ans]=CNT[posr][ans]-CNT[posl-1][ans];
		}
        //莫队小四只
		while(l>Li)add(posl,posr,a[--l],1);
		while(r<Ri)add(posl,posr,a[++r],1);
		printf("%d\n",mp[ans]);
		while(l<LL)add(posl,posr,a[l++],-1);
		while(r>RR)add(posl,posr,a[r--],-1);
		if(belong[Li]+1<belong[Ri]){//减去中间夹的特征区间的众数个数
			col[anss[posl][posr]]-=CNT[posr][anss[posl][posr]]-CNT[posl-1][anss[posl][posr]];
	    }
    }

	return Elaina;
}
/*
6 3 
1 2 3 2 1 2 
1 5 
3 6 
1 5 


10 0
1 2 3 4 5 6 9 9 9 9
*/

都看到这了,真的不点个赞吗(>ω<*)

标签:le,int,莫队,Violet,区间,蒲公英,col,P4168
From: https://www.cnblogs.com/Elaina-0/p/18146840

相关文章

  • [BZOJ4358]permu树上莫队
    先放代码晚上补(争取)#include<bits/stdc++.h>#definefo(x,y,z)for(int(x)=(y);(x)<=(z);(x)++)#definefu(x,y,z)for(int(x)=(y);(x)>=(z);(x)--)typedeflonglongll;usingnamespacestd;inlineintqr(){ charch=getchar();intx=0,f=1; for(;ch<&......
  • C117 莫队配合 bitset P4688 [Ynoi2016] 掉进兔子洞
    视频链接:C117莫队配合bitsetP4688[Ynoi2016]掉进兔子洞_哔哩哔哩_bilibili   LuoguP4688[Ynoi2016]掉进兔子洞//莫队配合bitsetO(n*sqrt(n))#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<bitset>usin......
  • 莫队
    莫队介绍利用分块进行处理的离线算法;时间复杂度普遍为\(O(n\sqrt{n})\);但会被卡实现思路对答案的查询在已知区间的情况下暴力寻找的目标区间的贡献;对于已知当前\([L,R]\)区间,一共有\(4\)种情况:加上当前区间左边一格的贡献:Add(--L);先将当前的下标......
  • P4168 [Violet] 蒲公英(题解)
    题目题目描述输入格式输出格式数据范围![]样例输入:63123212153615输出:121思路暴力本题求区间内的最小众数,容易想到去用数组sum[i]表示第i种花的个数,在去便利比较,但是复杂度nm一定会T,这时候就要对暴力进行优化。分块优化1如果我们将所......
  • 莫队
    简介莫队是一种离线求区间信息的算法,可以做到\(O((N+Q)\cdot\sqrt{N})\)。莫队中使用了分块的思想。首先考虑一个问题:给定一个长度为\(N\)序列\(A\)和\(Q\)次询问,每次询问查询区间\([X_i,Y_i]\)的和。(请先忘掉前缀和、线段树、树状数组什么的)比如以下数据:54322......
  • 莫队
    莫队是一种对于询问做转移的算法。对于可以离线,运算可逆的题目。如果按题目给的顺序操作,可以被以下数据hack11nn11nn11nn11nn...时间复杂度\(O(n^2)\)。我们可以通过某一些排序来降低时间复杂度。首先,把这个序列分成\(\sqrt{n}\)块,每一块按右......
  • C116 莫队二次离线 P4887 莫队二次离线
    视频链接:     LuoguP4887【模板】莫队二次离线(第十四分块(前体))//莫队二次离线O(n*sqrt(n)+n*C(k,14))#include<iostream>#include<cstring>#include<algorithm>#include<cmath>#include<vector>usingnamespacestd;constintN=100005;......
  • 莫队
    查询区间每个数出现的个数,离线算法,O(nsqrt(n))一、普通莫队题目链接https://www.luogu.com.cn/problem/P2709题目大意题目代码#include<iostream>#include<algorithm>#include<cmath>#definelllonglongconstintN=5e4+5;usingnamespacestd;intn,m,k,block......
  • 莫队学习笔记
    目录普通莫队初遇——从暴力谈起困境——乱跑的指针优化——顺路而为之带修莫队参考资料普通莫队初遇——从暴力谈起我们通过一道例题来讨论普通莫队。题目链接。观察数据范围,一个很直接的想法是:开一个数组\(cnt\),\(cnt_i\)表示在询问的区间内数字\(i\)出现的次数。对于......
  • #莫队二次离线,根号分治#洛谷 5398 [Ynoi2018] GOSICK
    题目\(m\)组询问求\(\sum_{l\leqi,j\leqr}[a_i\bmoda_j==0],n,m,a_i\leq5\times10^5\)分析设\(f(l,r,x)\)表示\(i或j\in[1,x],i或j\in[l,r]\)时的答案,\(g_x\)表示\([1,x]\)的答案,根号的做法可以通过三秒由于涉及区间内的求值,需要在莫队的基础上二次离线,那......