题目描述
分块
你考虑有一堆人,价格为x的进去了出来会变成啥样。
那么肯定是找到这堆人所持价格的最大值y,如果x>y,出来的还是y,否则x会变成某个人手里的,然后出来的是y。
我们考虑分块,每个块维护一个数堆。
如果x要经过一个块,可以丢进数堆,再取出一个最大值。然后还要给这个块打上一个标记。
但是对于零散的不是很好做,即重构块,我们如何快速得到每个位置经过一系列标记后的值?
注意这个问题具有高度对称性,即一盘寿司一盘寿司的经过人,可以看做一个一个人走过寿司。
对标记也维护堆,然后枚举每个人,它手里的是x,那么把x丢进标记堆,再取出一个最小值,就是这个人更新后的。
堆要手打。
标记只在重构块时才丢进堆中,而且丢进堆前先排序。
一个块如果没有标记可以不重构。
一个x经过一个块如果还是x那么不给这个块打标记。
加上上述优化来卡常。
#include<cstdio>
#include<algorithm>
#include<queue>
#include<vector>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=400000+10,maxq=25000+10,B=633;
//priority_queue<int> tt[B+10],num[B+10];//num big tt small
int tt[B+10][maxq],num[B+10][B+10],zt[B+10],zn[B+10];
int bj[B+10][maxq],zb[B+10];
int a[maxn],belong[maxn];
int i,j,k,l,r,x,y,t,n,m,tot;
int read(){
int x=0,f=1;
char ch=getchar();
while (ch<'0'||ch>'9'){
if (ch=='-') f=-1;
ch=getchar();
}
while (ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void push1(int x,int v){
tot=zn[x];
num[x][++tot]=v;
int k=tot;
while (k>1){
if (num[x][k]>num[x][k/2]) swap(num[x][k],num[x][k/2]);
else break;
k/=2;
}
zn[x]=tot;
}
int pop1(int x){
int t=num[x][1];
tot=zn[x];
num[x][1]=num[x][tot];
tot--;
int k=1,j;
while (k*2<=tot){
if (k*2+1>tot||num[x][k*2]>num[x][k*2+1]) j=k*2;else j=k*2+1;
if (num[x][k]<num[x][j]) swap(num[x][k],num[x][j]);
else break;
k=j;
}
zn[x]=tot;
return t;
}
void push2(int x,int v){
tot=zt[x];
tt[x][++tot]=v;
int k=tot;
while (k>1){
if (tt[x][k]<tt[x][k/2]) swap(tt[x][k],tt[x][k/2]);
else break;
k/=2;
}
zt[x]=tot;
}
int pop2(int x){
int t=tt[x][1];
tot=zt[x];
tt[x][1]=tt[x][tot];
tot--;
int k=1,j;
while (k*2<=tot){
if (k*2+1>tot||tt[x][k*2]<tt[x][k*2+1]) j=k*2;else j=k*2+1;
if (tt[x][k]>tt[x][j]) swap(tt[x][k],tt[x][j]);
else break;
k=j;
}
zt[x]=tot;
return t;
}
void rebuild(int x){
if (zb[x]==0){
zt[x]=zn[x]=0;
return;
}
int i,t;
sort(bj[x]+1,bj[x]+zb[x]+1);
fo(i,1,zb[x]) push2(x,bj[x][i]);
zb[x]=0;
fo(i,(x-1)*B+1,min(x*B,n)){
push2(x,a[i]);
//tt[x].push(-a[i]);
a[i]=pop2(x);
/*a[i]=-tt[x].top();
tt[x].pop();*/
}
zt[x]=zn[x]=0;
/*while (!tt[x].empty()) tt[x].pop();
while (!num[x].empty()) num[x].pop();*/
}
int main(){
freopen("sushi.in","r",stdin);freopen("sushi.out","w",stdout);
n=read();m=read();
fo(i,1,n){
a[i]=read();
belong[i]=(i-1)/B+1;
push1(belong[i],a[i]);
//num[belong[i]].push(a[i]);
}
while (m--){
j=read();k=read();x=read();
l=belong[j];r=belong[k];
if (l==r&&j<=k){
rebuild(l);
//if (j<k){
fo(i,j,k)
if (x<a[i]) swap(x,a[i]);
//}
/*else{
fo(i,j,min(l*B,n))
if (x<a[i]) swap(x,a[i]);
fo(i,(l-1)*B+1,k)
if (x<a[i]) swap(x,a[i]);
}*/
fo(i,(l-1)*B+1,min(l*B,n)) {
push1(l,a[i]);
//num[l].push(a[i]);
}
printf("%d\n",x);
continue;
}
rebuild(l);
fo(i,j,min(l*B,n))
if (x<a[i]) swap(x,a[i]);
fo(i,(l-1)*B+1,min(l*B,n)){
push1(l,a[i]);
//num[l].push(a[i]);
}
l=l%belong[n]+1;
while (l!=r){
push1(l,x);
//num[l].push(x);
y=pop1(l);
/*x=num[l].top();
num[l].pop();*/
if (y!=x){
bj[l][++zb[l]]=x;
//push2(l,x);
//tt[l].push(-x);
x=y;
}
l=l%belong[n]+1;
}
rebuild(r);
fo(i,(r-1)*B+1,k)
if (x<a[i]) swap(x,a[i]);
fo(i,(r-1)*B+1,min(r*B,n)){
push1(r,a[i]);
//num[r].push(a[i]);
}
printf("%d\n",x);
}
}