建议加上标签”倍增“
查看原帖
建议加上标签”倍增“
600441
ZhongYuLin楼主2023/8/28 20:59

rt。理由:询问3可以转化为一道经典的倍增题目:对于一个序列a,求最大的i,使得第一项到第i项的和小于一个给定的值,可以将二分的O(logN)优化为O(log答案)。详见代码:

#include<bits/stdc++.h>
using namespace std;
const int maxn=1e6;
struct node{
	long long l,r;
}a[maxn];
long long c,q,in1,in2,tot,ltot=1,dele,len,d[maxn];
bool b[maxn];
deque<int>que;
int main(){
	cin>>c>>q;
	while(q--){
		cin>>in1;
		if(in1==1){
			cin>>in2;
			a[++tot]={1,in2};
			while(!que.empty()&&a[que.back()].r<=in2) que.pop_back();
			que.push_back(tot);
			len+=in2;
			d[tot]=d[tot-1]+in2;
		}
		else if(in1==2){
			cin>>in2;
			dele+=in2;
			while(in2){
				if(a[ltot].r-a[ltot].l+1>in2){
					a[ltot].l+=in2;
					in2=0;
				}else{
					in2-=a[ltot].r-a[ltot].l+1;
					b[ltot++]=1;
				}
			}
		}else if(in1==3){
			cin>>in2;
			in2+=dele;
			//d[i]是前缀和数组 
			//查询最大的i,使得 d[i]<in2,使用倍增算法,非常经典 
			long long p=1,k=0,sum=0;
			while(p)
				if(k+p<=tot&&sum+d[k+p]-d[k]<in2)
					sum+=d[k+p]-d[k],k+=p,p*=2;
				else p/=2;
			
			printf("%d\n",in2-d[k]);
		}else{
			while(b[que.front()]) que.pop_front();
			printf("%d\n",a[que.front()].r);
		}
	}
	return 0;
}
2023/8/28 20:59
加载中...