我们注意到这道题中最多有 $(n+q)$ 个数被加入,而每个数最多被删除一次,因此每次操作 $O(logn)$的复杂度是可以接受的。
我们对于$1..100000$之间每个数分别开一个set,维护这个数出现在哪些位置,这样我们就可以非常方便地维护每个数的前驱和后继。
同时我们开一个数组保存每个位置的数是多少。
对于加入操作,我们直接将这个数的坐标加入相应的set,并且从占据这个坐标的数所对应的set中删除这个坐标。
对于删除操作,我们维护两个迭代器(一个向左,一个向右),每次删除距离询问位置较近的一个,然后移动这个迭代器,直到删除次数耗尽为止。
每次加入一个数和删除一个数的复杂度均为 $O(logn)$ ,总复杂度为 $O((n+q)log_(n+q))$。
#include<bits/stdc++.h> #define iter set<int>::iterator using namespace std; const int N=200050; int n,Q,a[N]; set<int> s[N]; vector<int> v; int read(){ int x=0;char ch=getchar(); while(ch<'0' || ch>'9')ch=getchar(); while(ch>='0' && ch<='9')x=x*10+ch-'0',ch=getchar(); return x; } int main(){ n=read(); for(int i=1,x;i<=n;++i)x=read(),a[i]=x,s[x].insert(i); for(Q=read();Q--;){ int pos=read(),type=read(),E=read(),Dpos=read(),Dtype=read(); iter Pre=s[type].upper_bound(pos),Nxt=Pre; while(E && !s[type].empty() && (Pre!=s[type].begin() || Nxt!=s[type].end())){ E--; int flag=0; if(Pre!=s[type].begin()){ if(Nxt==s[type].end())v.push_back(*(--Pre)),flag=1; else if(pos-(*(--Pre))<=(*Nxt)-pos)v.push_back(*Pre),flag=1; else ++Pre; } if(!flag)v.push_back(*Nxt),Nxt++; } sort(v.begin(),v.end()); printf("%d ",v.size()); for(int i=0;i<v.size();i++)printf("%d ",v[i]),s[type].erase(v[i]),a[v[i]]=0; puts(""); v.clear(); if(a[Dpos])s[a[Dpos]].erase(Dpos); a[Dpos]=Dtype;s[Dtype].insert(Dpos); } return 0; }