JZOJ-senior-5967. 常数国

Time Limits: 6000 ms Memory Limits: 681984 KB

Description

JZOJ-senior-5967. 常数国_第1张图片

Input&Output

JZOJ-senior-5967. 常数国_第2张图片

Sample Input&Sample Output

JZOJ-senior-5967. 常数国_第3张图片
JZOJ-senior-5967. 常数国_第4张图片

Data Constraint

JZOJ-senior-5967. 常数国_第5张图片

Solution

分块,对于每个块,开两个multiset
一个维护块内有哪些数,另一个维护有哪些未下传的标记
对于每次操作,在散块(即头尾)先下传标记再把最大提出来
下传标记就是暴力重构,对于每个位置,如果它比最小标记大,那么就更新成最小的标记
(因为标记里的每个数都要通过当前这一整块,所以最终这个位置的数一定是标记里最小的)
具体操作:在multiset里删除最小的标记并加入这个被替换出来的数
在整块里面就是将前一块传下来的那个数和这一块的最大值比较
如果传下来的那个数比较大,那么对这个块不会有影响
否则传到下一块的就是当前块的最大值,对应地维护multiset就好了
具体操作:在multiset里加入传进来的这个数并删除最大那个数
时间复杂度 O ( Q N l o g Q ) O(Q\sqrt{N}logQ) O(QN logQ)

温馨提示:由于常数巨大,代码比较丑的加入set时请使用整段加入

Code

#include
#include
#include
#include
#include

#define fo(i,a,b) for(int i=a;i<=b;++i)
#define fd(i,a,b) for(int i=a;i>=b;--i)
#define P(c) putchar(c)

using namespace std;

const int N=4e5+5,M=650;
int n,q,v,opl,opr,len,a[N],c[N],B[N];
multiset<int> E[M],P[M];
multiset<int>::iterator it;

inline void read(int &n)
{
	int x=0,w=0; char ch=0;
	while(!isdigit(ch)) w|=ch=='-',ch=getchar();
	while(isdigit(ch)) x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	n=w?-x:x;
}

inline void write(int x)
{
	if(x<0) x=-x,putchar('-');
	if(x>9) write(x/10);
	putchar(x%10+'0');
}

void down(int k)
{
	fo(i,(k-1)*len+1,k*len) if(!P[k].empty())
	{
		int x=*P[k].begin();
		if(a[i]>x) P[k].erase(P[k].begin()),P[k].insert(a[i]),a[i]=x;
	}
	P[k].clear();
}

void solve(int l,int r)
{
	down(B[l]);
	int tmp=v;
	fo(i,l,min(r,B[l]*len)) if(a[i]>v) swap(a[i],v);
	if(v!=tmp)
	{
		it=E[B[l]].find(-v);
		if(it!=E[B[l]].end()) E[B[l]].erase(it);
		E[B[l]].insert(-tmp);
	}
	fo(i,B[l]+1,B[r]-1) if(-*E[i].begin()>v)
	{
		int y=-*E[i].begin();
		P[i].insert(v);
		E[i].erase(E[i].begin()),E[i].insert(-v);
		v=y;
	}
	if(B[l]!=B[r])
	{
		down(B[r]);
		int tmp=v;
		fo(i,(B[r]-1)*len+1,r) if(a[i]>v) swap(a[i],v);
		if(v!=tmp)
		{
			it=E[B[r]].find(-v);
			if(it!=E[B[r]].end()) E[B[r]].erase(it);
			E[B[r]].insert(-tmp);
		}
	}
}

int main()
{
	freopen("in.in","r",stdin);
	freopen("in.out","w",stdout);
	read(n),read(q),len=2000;
	fo(i,1,n) read(a[i]),B[i]=(i-1)/len+1,c[i]=-a[i];
	fo(i,1,B[n])
	{
		int st=(i-1)*len+1,en=min(n,i*len);
		E[i].insert(c+st,c+en+1);
	}
	fo(i,1,q)
	{
		read(opl),read(opr),read(v);
		if(opl>opr) solve(opl,n),solve(1,opr); else solve(opl,opr);
		write(v),P('\n');
	}
}

你可能感兴趣的:(分块)