P9588 队列

思路

观察发现 \(x\)\(y\)\(z\) 都可以很大,所以如果直接用队列老老实实地操作,肯定过不了。

因为每次加入都是 \(1,2,3,\cdots x\) 所以这段是连续的,所以我们考虑一段一段的存入队列,记录每一段的左右端点。

操作 \(2\) 的删除,就一段一段地删除,如果删不完一段,就改这一段的左端点。

操作 \(3\) 的查询可以记录每段的长度的前缀和(如果用操作 \(2\) 的办法的话就会 TLE)。

操作 \(4\) 的最大值只可能出现在每段的 \(x\),考虑用 multiset 存 \(x\),但是不知道为什么我的 multiset 炸了,改成 map 和 set 才对。

AC code

#include<bits/stdc++.h>
using namespace std;
struct node{long long l,r;}dl[200005];
long long c,q,op,x,he,ta,len[200005];
set<long long>s;
map<long long ,int>m;
int main()
{
	scanf("%lld%lld",&c,&q);
	while(q--)
	{
		scanf("%lld",&op);
		if(op==1) scanf("%lld",&x),dl[++ta].l=1,dl[ta].r=x,s.insert(x),m[x]++,len[ta]=dl[ta].r+len[ta-1];
		else if(op==2)
		{
			scanf("%lld",&x);
			while(x>=dl[he+1].r-dl[he+1].l+1){x-=dl[he+1].r-dl[he+1].l+1,++he;if(m[dl[he].r]==1) s.erase(dl[he].r);m[dl[he].r]--;}
			if(x) dl[he+1].l+=x;
		}
		else if(op==3)
		{
			scanf("%lld",&x);
			x+=len[he]+dl[he+1].l-1;
			long long l=he,r=ta,mid,ansp;
			while(l<=r)
			{
				mid=l+r>>1;
				if(x>len[mid]) ansp=mid,l=mid+1;
				else r=mid-1;
			}
			printf("%lld\n",x-len[ansp]);
		}
		else
		{
			auto i=s.end();--i;
			printf("%lld\n",*i);
		}
	}
	return 0;
}
posted @ 2023-08-29 12:34  One_JuRuo  阅读(77)  评论(0编辑  收藏  举报