就找了两三道题,不过回滚莫队思路也好理解,代码实现也不难:
1、我们以块编号为第一关键字排序,右端点位置为第二关键字排序
2、询问时依次枚举区间,我们保留右端点的移量(右边单增),左端点则每次在这一个块中来回移动
3、下一个块时,清空统计答案重做
所以对于每一个块:左端点每次操作√n,右端点总共移n,均摊√n,因此时间复杂度保证了n√n
题目描述
给出一个长为 n 的数列,以及 n 个操作,操作涉及询问区间的最小众数。
输入格式
第一行输入一个数字 n。
第二行输入 n个数字,第 i 个数字为 ai,以空格隔开。
接下来输入 n 行询问,每行输入两个数字 l、r以空格隔开。
表示查询位于[l,r]的数字的众数。
输出格式
对于每次询问,输出一行一个数字表示答案。
样例
样例输入
4
1 2 2 4
1 2
1 4
2 4
3 4
样例输出
1
2
2
2
#include
using namespace std;
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
const int N = 1e5;
int n,siz,k[N+10],bl[N+10];
struct Que{
int L,r,idx;
}q[N+10];
bool cmp(const Que&A,const Que&B){
return bl[A.L]^bl[B.L]?A.L=cur_num){
if(num[rp[x]]==cur_num&&k[x]cur_num)cur_ans=k[x],cur_num=num[rp[x]];
}
}
inline void addl(int x,int &ans,int &Num){
++num[rp[x]];
if(num[rp[x]]>=Num){
if(num[rp[x]]==Num&&k[x]Num)ans=k[x],Num=num[rp[x]];
}
}
inline void remove(int x){
--num[rp[x]];
}
inline void solv(){
int L,r,lim;
Inc(i,1,n){
if(bl[q[i].L]^bl[q[i-1].L]){//下一个块,初始化
memset(num,0,sizeof(num));
L=lim=bl[q[i].L]*siz+1;
r=bl[q[i].L]*siz;
cur_ans=cur_num=0;
}
if(bl[q[i].L]==bl[q[i].r]){//不用移动r,直接暴力扫√n ,也是分块散块的处理思想呢
int ans,nownum=0;
Inc(j,q[i].L,q[i].r)++num[rp[j]];
Inc(j,q[i].L,q[i].r)if(num[rp[j]]>=nownum){
if(num[rp[j]]==nownum&&k[j]nownum)ans=k[j],nownum=num[rp[j]];
}
Inc(j,q[i].L,q[i].r)--num[rp[j]];
Ans[q[i].idx]=ans;
continue;
}
while(rq[i].L)addl(--L,now,nownum);
Ans[q[i].idx]=now;
while(L
IOI国历史研究的第一人——JOI教授,最近获得了一份被认为是古代IOI国的住民写下的日记。JOI教授为了通过这份日记来研究古代IOI国的生活,开始着手调查日记中记载的事件。
日记中记录了连续N天发生的时间,大约每天发生一件。
事件有种类之分。第i天(1<=i<=N)发生的事件的种类用一个整数Xi表示,Xi越大,事件的规模就越大。
JOI教授决定用如下的方法分析这些日记:
1.选择日记中连续的一些天作为分析的时间段
2.事件种类t的重要度为t*(这段时间内重要度为t的事件数)
3.计算出所有事件种类的重要度,输出其中的最大值
现在你被要求制作一个帮助教授分析的程序,每次给出分析的区间,你需要输出重要度的最大值。
第一行两个空格分隔的整数N和Q,表示日记一共记录了N天,询问有Q次。
接下来一行N个空格分隔的整数X1...XN,Xi表示第i天发生的事件的种类
接下来Q行,第i行(1<=i<=Q)有两个空格分隔整数Ai和Bi,表示第i次询问的区间为[Ai,Bi]。
输出Q行,第i行(1<=i<=Q)一个整数,表示第i次询问的最大重要度
5 5
9 8 7 8 9
1 2
3 4
4 4
1 4
2 4
9
8
8
16
16
1<=N<=10^5
1<=Q<=10^5
1<=Xi<=10^9 (1<=i<=N)
#include
using namespace std;
#define int long long
#define N 100010
#define Inc(i,L,r) for(register int i=(L);i<=(r);++i)
#define Red(i,r,L) for(register int i=(r);i>=(L);--i)
int n,q,siz,v[N],rp[N],bl[N],imp[N];
struct Sec{
int L,r,idx;
}a[N];
bool cmp(const Sec&A,const Sec&B){
return bl[A.L]^bl[B.L]?A.La[i].L)add(--L),ans1=max(ans1,sum[rp[L]]);
while(L
给定序列,求[l,r]区间内数字相同的数的最远距离。
题目传送门
#include
using namespace std;
const int Maxn=100005;
int n,m,k,siz,a[Maxn],bl[Maxn];
int t[Maxn],mnl[Maxn],mxr[Maxn];
int ret,ans[Maxn];
struct seq{
int l,r,idx;
}q[Maxn];
bool cmp(const seq&A,const seq&B){
return bl[A.l]!=bl[B.l]?A.l