[LOJ2736] [JOISC 2016 3日目]寿司(ヒープブロック+)
フェイス質問
n個の点の環を考えると、各点は環初期重量有する(a_iを\)\を
クエリーQが与えられると、毎時間クエリは区間[L、R]、及び値Aは、以下の定義の変化を与えられます
for (int i = l; i <= r; i++) if(a[i] > A) swap(a[i],A);
各クエリに対して、答えは最終区間[L、R]値をトラバース。
分析
これは、一般的な構造のメンテナンスとデータを交換シーケンスブロックを考慮することが困難であると考えられます。
まず、あるブロックの数のすべてが<Aは、その後、変更は何が起こるかあればことがわかりました。そうでない場合には、各ブロックの最大数がA置換され、Aとなる((私は[L、R&LT])で\ \ MAX(A、MAX(a_iをを)))\。したがって、各ブロック内のルートスタックの多数のメンテナンスは、スタックの上部のみが変更時刻がブロックされる電流よりも小さくなっています。
通常、ブロック・ルーチン、変性ブロックはちょうど直接タイル表面のシミュレーション問題間で行き来することができ、マークを作りたいとき。タグは、押し下げたときに端部を横断し、再構成されたブロックの両端べき
マークが押し下げ考えてみましょう、我々は二つの異なるマーカーについての斧は、Ayのは、斧<Ayの場合、最大数は斧を交換することになることを見出しました。非常に小さいヒープストレージルートタグを有する各ブロック、再構成されたブロックのトラバーサル[I]> A [i]が小さいヒープルートに挿入し、次に交換される元の場合(Aが、[I]) 。これは実証することができ、その複数のマークは、各交換について同じであるブロックに進みます。
コード
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define maxn 400000
#define maxb 1000
using namespace std;
inline void qread(int &x) {
x=0;
int sign=1;
char c=getchar();
while(c<'0'||c>'9') {
if(c=='-') sign=-1;
c=getchar();
}
while(c>='0'&&c<='9') {
x=x*10+c-'0';
c=getchar();
}
x=x*sign;
}
inline void qprint(int x) {
if(x<0) {
putchar('-');
qprint(-x);
} else if(x==0) {
putchar('0');
return;
} else {
if(x>=10) qprint(x/10);
putchar('0'+x%10);
}
}
int n,m;
int a[maxn+5];
int bsz;
int bel[maxn+5];
inline int lb(int id){
return bsz*(id-1)+1;
}
inline int rb(int id){
return bsz*id>=n?n:bsz*id;
}
priority_queue<int>num[maxb+5];//大根堆,存储每一块中的数
priority_queue<int,vector<int>,greater<int> >mark[maxb+5] ;//小根堆,存储每一个块上替换标记
//从小到大是因为序列中的数会被优先换成小的标记
void rebuild(int id){//重构每个块,不管是整块替换还是部分替换,都要调用rebuild
while(!num[id].empty()) num[id].pop();
for(int i=lb(id);i<=rb(id);i++){
num[id].push(a[i]);
}
}
void push_down(int id){
if(!mark[id].empty()){
for(int i=lb(id);i<=rb(id);i++){
int v=mark[id].top();
if(v<a[i]){
swap(a[i],v);
mark[id].pop();
mark[id].push(v);//把a[i]与v交换
}
}
while(!mark[id].empty()) mark[id].pop();
rebuild(id);
}
}
int update(int l,int r,int A){
push_down(bel[l]);//非整块操作,必须下推标记
for(int i=l;i<=min(r,rb(bel[l]));i++){
if(A<a[i]) swap(a[i],A);
}
rebuild(bel[l]);
for(int i=bel[l]+1;i<bel[r];i++){
int v=num[i].top();
if(v>A){ //如果最大值比A小,就不替换了
num[i].pop();
num[i].push(A);
mark[i].push(A);
swap(A,v);
//整块修改的时候只需要替换最大值,剩下的操作push_down的时候完成
}
}
if(bel[l]!=bel[r]){
push_down(bel[r]);
for(int i=lb(bel[r]);i<=r;i++){
if(A<a[i]) swap(a[i],A);
}
rebuild(bel[r]);
}
return A;
}
int main(){
int l,r,A;
qread(n);
qread(m);
for(int i=1;i<=n;i++) qread(a[i]);
bsz=sqrt(n);
for(int i=1;i<=n;i++){
bel[i]=(i-1)/bsz+1;
num[bel[i]].push(a[i]);
}
for(int i=1;i<=m;i++){
qread(l);
qread(r);
qread(A);
if(l<=r){
A=update(l,r,A);
}else{
A=update(l,n,A);
A=update(1,r,A);
}
// printf("db:");
qprint(A);
putchar('\n');
}
}