【莫队】【链表】三校联考1015T3

题意:

在这里插入图片描述


分析:

啊啊啊啊我发明的算法居然以前有过。。。。https://blog.csdn.net/qq_34454069/article/details/80184286

方法其实很简单。。。首先,把所有未加入的点放在一个双向链表里。

然后,每次插入一个值,就相当于把这个点从双向链表中删除。每次删除的时候,统计一下其左侧和右侧的,已经从链表中删去(即已经插入的)点的个数即可。

然而,问题来了,如果做莫队的话。。有个小问题:插入值还好,但如果要删除一个值,你就会把原来某个连续的区间,划分为两部分。然而这样一来,你无法确定剩下的所有连续区间的最大长度。

所以,不能删除的莫队?就是我之前讲的那个算法(学名叫回滚莫队)。

排序方式还是一样的,只不过这里对每个左端点在一个块内的分别处理:
首先,先清空之前的状态。
在这里插入图片描述
然后,右端点向右拓展直到某个询问的右端点。
在这里插入图片描述
现在保存所有当前答案。然后再依次插入左区间的点
在这里插入图片描述
得到答案后,再依次撤回操作(具体实现是通过栈暴力存储每次修改的地方,参见代码)
再做下一次操作。
复杂度 O ( N N ) O(N\sqrt N) O(NN )

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<stack> 
#define MAXN 100010
#define SF scanf
#define PF printf
using namespace std;
typedef pair<int,int> pii;
int a[MAXN],blo[MAXN];
int ans[MAXN],ansx;
struct node{
	int l,r,id;
	bool operator <(const node &a) const{
		if(blo[l]!=blo[a.l])
			return blo[l]<blo[a.l];
		return r<a.r;	
	}
}q[MAXN];

int lp[MAXN],rp[MAXN];
struct chag{
	int l,orgl;
	int r,orgr;	
	chag () {}
	chag (int l1,int ol1,int r1,int or1):l(l1),orgl(ol1),r(r1),orgr(or1) {}
};
stack<chag> s;
void add(int x,bool flag){
	int sizl=x-lp[x]-1;
	int sizr=rp[x]-x-1;
	ansx=max(ansx,sizl+sizr+1);
	if(flag)
		s.push(chag(lp[x],rp[lp[x]],rp[x],lp[rp[x]]));
	rp[lp[x]]=rp[x];
	lp[rp[x]]=lp[x];
}
void restore(){
	while(!s.empty()){
		int l=s.top().l;
		int r=s.top().r;
		int orgl=s.top().orgl;
		int orgr=s.top().orgr;
		rp[l]=orgl;
		lp[r]=orgr;
		s.pop();
	}
}
int n,m;
void solve(int lasx,int L,int R){
	int las=lasx-1;
	for(int i=1;i<=n;i++){
		lp[i]=i-1;
		rp[i]=i+1;
	}
	ansx=0;
	while(q[L].r<lasx&&L<=R){
		for(int i=q[L].l;i<=q[L].r;i++)
			add(a[i],1);
		ans[q[L].id]=ansx;
		restore();
		ansx=0;
		L++;
	}
	for(int i=L;i<=R;i++){
		while(las<q[i].r)
			add(a[++las],0);
		int pans=ansx;
		for(int j=lasx-1;j>=q[i].l;j--)
			add(a[j],1);
		ans[q[i].id]=ansx;
		restore();
		ansx=pans;
	}
}
int main(){
	freopen("ants.in","r",stdin);
	freopen("ants.out","w",stdout);
	SF("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
		SF("%d",&a[i]);
	for(int i=1;i<=m;i++){
		SF("%d%d",&q[i].l,&q[i].r);
		q[i].id=i;
	}
	int BASE=int(sqrt(n));
	for(int i=1;i<=n;i++)
		blo[i]=i/BASE+1;
	sort(q+1,q+1+m);
	int las=1;
	for(int i=2;i<=m;i++)
		if(blo[q[i].l]!=blo[q[i-1].l]){
			solve(blo[q[i-1].l]*BASE,las,i-1);
			las=i;
		}
	solve(blo[q[las].l]*BASE,las,m);
	for(int i=1;i<=m;i++)
		PF("%d\n",ans[i]);
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值