版权声明:转载请声明 https://blog.csdn.net/ezoiHQM/article/details/82555284
权限题题目链接
这道题其实是一道可并堆的经典题。
每一个盒子维护一个小根堆,存储以这个点为左端点的右端点。一旦一个盒子里的被取空,就将这个盒子和下一个盒子合并,然后不断判断这个堆的堆顶是否小于下一个盒子的编号来统计答案。合并就用左偏树+并查集啦。
如果有误在评论区吼一声哦!
代码:
#include<cstdio>
#include<cctype>
#include<algorithm>
using namespace std;
int n,m,q,lastans,a[100010],rt[100010],lch[100010],rch[100010],v[100010],dep[100010],f[100010];
int find(int x){
return x==f[x]?x:f[x]=find(f[x]);
}
int merge(int x,int y){
if(!x||!y)
return x|y;
if(v[x]>v[y])
swap(x,y);
rch[x]=merge(rch[x],y);
if(dep[lch[x]]<dep[rch[x]])
swap(lch[x],rch[x]);
dep[x]=dep[rch[x]]+1;
return x;
}
int rd(){
int x=0;
char c;
do c=getchar();
while(!isdigit(c));
do{
x=(x<<1)+(x<<3)+(c^48);
c=getchar();
}while(isdigit(c));
return x;
}
int main(){
n=rd(),m=rd();
for(int i=1;i<=n;i++){
a[i]=rd();
f[i]=i;
}
f[n+1]=n+1;
for(int i=1;i<=m;i++){
int l=rd(),r=rd();
v[i]=r;
rt[l]=merge(rt[l],i);
}
q=rd();
while(q--){
int x=rd();
x=(x+lastans-1)%n+1;
a[x]--;
if(!a[x]){
f[x]=find(x+1);
while(rt[x]&&v[rt[x]]<f[x]){
lastans++;
rt[x]=merge(lch[rt[x]],rch[rt[x]]);
}
rt[f[x]]=merge(rt[f[x]],rt[x]);
}
printf("%d\n",lastans);
}
return 0;
}