【NOI2017模拟6.23】回转寿司
2017-06-23 21:30
260 查看
题目大意
有n个人排成一个圆环,每个人初始有一个数字a[i],有m轮操作,每轮操作选择一段连续的人并给出一个数字x,按顺时针顺序比较x和a[i],如果x小于a[i],就那么交换a[i]和x1≤n≤4×105
1≤m≤2.5∗104
解法
考虑分块,那么对于一个块来说,如果当前某个数x进去了,那么出来的要不是x要不就是这个块的最大值,所以对每个块维护一个大根堆。而对于块内的重构,由于本题有很好的性质:标记的处理和a[]的变化是具有对称性的,就是说重构时只要维护一个对于标记的小根堆,然后从左到右扫一遍。
Code
#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<cmath> #include<set> #include<bitset> #include<map> #define fo(i,a,b) for(int i=a;i<=b;i++) #define fd(i,a,b) for(int i=a;i>=b;i--) using namespace std; typedef long long LL; typedef double db; int get(){ char ch; while(ch=getchar(),(ch<'0'||ch>'9')&&ch!='-'); if (ch=='-'){ int s=0; while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0'; return -s; } int s=ch-'0'; while(ch=getchar(),ch>='0'&&ch<='9')s=s*10+ch-'0'; return s; } const int N = 400010; const int Q = 25010; const int blk = 635; const int B = 640; int n,q; struct heap0{ int a[B]; int n; int& operator [](int x){return a[x];} int top(){return a[1];} void pop(){ int x=1; a[1]=a[n--]; while(x*2<=n){ int t=x*2; if (t<n&&a[t+1]>a[t])t++; if (a[t]<=a[x])break; swap(a[t],a[x]); x=t; } } void insert(int v){ a[++n]=v; int x=n; while(x>1&&a[x]>a[x>>1]){ swap(a[x],a[x>>1]); x>>=1; } } }a[B]; struct heap1{ int a[Q]; int n; int& operator [](int x){return a[x];} int top(){return a[1];} void pop(){ int x=1; a[1]=a[n--]; while(x*2<=n){ int t=x*2; if (t<n&&a[t+1]<a[t])t++; if (a[t]>=a[x])break; swap(a[t],a[x]); x=t; } } void insert(int v){ a[++n]=v; int x=n; while(x>1&&a[x]<a[x>>1]){ swap(a[x],a[x>>1]); x>>=1; } } }t[B]; int be ,rig ,lef ; int val ; void rebuild(int x){ a[x].n=0; if (!t[x].n)return; fo(i,lef[x],rig[x]){ int tp=t[x].top(); if (tp<val[i]){ t[x].pop(); t[x].insert(val[i]); val[i]=tp; } } t[x].n=0; } void putnew(int x){ a[x].n=0; fo(i,lef[x],rig[x])a[x][++a[x].n]=val[i]; sort(a[x].a+1,a[x].a+a[x].n+1); fo(i,1,a[x].n/2)swap(a[x][a[x].n-i+1],a[x][i]); } void solve(int l,int r,int &v){ if (be[l]==be[r]){ rebuild(be[l]); fo(i,l,r) if (v<val[i])swap(v,val[i]); putnew(be[l]); return; } int lt=be[l],rt=be[r]; if (l>lef[lt]){ rebuild(lt); for(int i=l;be[i]==lt;i++) if (v<val[i])swap(v,val[i]); putnew(lt); lt++; } if (r<rig[rt]){ fo(i,lt,rt-1){ int tp=a[i].top(); if (v<tp){ a[i].pop(); a[i].insert(v); t[i].insert(v); v=tp; } } rebuild(rt); fo(i,rig[rt-1]+1,r) if (v<val[i])swap(v,val[i]); putnew(rt); } else fo(i,lt,rt){ int tp=a[i].top(); if (v<tp){ a[i].pop(); a[i].insert(v); t[i].insert(v); v=tp; } } } int main(){ freopen("sushi.in","r",stdin); freopen("sushi.out","w",stdout); n=get();q=get(); fo(i,1,n)be[i]=i/blk+1; fo(i,1,n)rig[be[i]]=i; fd(i,n,1)lef[be[i]]=i; fo(i,1,n){ int x=get(); val[i]=x; a[be[i]].insert(x); } fo(cas,1,q){ int l=get(),r=get(),v=get(); if (l>r){ solve(l,n,v); solve(1,r,v); } else solve(l,r,v); printf("%d\n",v); } fclose(stdin); fclose(stdout); return 0; }
相关文章推荐
- JZOI【NOI2017模拟3.30】轮回
- 【NOI2017模拟3.30】轮回(根号算法,暴力)
- 【JZOJ5040】【NOI2017模拟4.2】押韵
- 【NOI2017模拟4.2】查询【线段树】
- 【JZOJ5043】【NOI2017模拟4.4】保持平衡
- 【NOI2017模拟.4.1】Shoes【DP决策单调性,主席树,分治】
- 【NOI2017模拟4.4】保持平衡
- 【NOI2017模拟6.20】树形图求和
- NOI2017模拟3.8 总结
- 【NOI2017模拟3.25】跳蚤王国
- [JZOJ5036]【NOI2017模拟3.30】原谅
- [JZOJ100003]【NOI2017模拟.4.1】 Tree
- 【JZOJ5036】【NOI2017模拟3.30】原谅
- 【JZOJ5039】【NOI2017模拟4.2】查询
- [JZOJ100004]【NOI2017模拟.4.1】 Dice
- 【NOI2017模拟.4.1】 Dice【概率,期望,DP,精度优化】
- 【NOI2017模拟4.5】机器人游戏
- 【NOI2017模拟6.26】A
- 【NOI2017模拟3.25】历史行程
- [JZOJ5037]【NOI2017模拟3.30】轮回