[noi1774]array
容易想到树套树,但数据范围太大,会超时
考虑平衡树的作用,就是将这个区间内的所有数排序,所以可以离线+归并来处理,预处理复杂度$o(n\log n)$,然后考虑维护:1.删除;2.询问
删除操作维护可以使用并查集,可以通过$\alpha(n)$的时间里快速找到每一个点的上和下元素
询问操作可以二分查找,这样的复杂度为$o(q\log^{2} n+q\log n\cdot \alpha(n))$,考虑优化掉二分的复杂度:对于每一个数,合并时记录左右区间中比他小/大且最接近的数,这样只需要在最开始二分一次就可以传递下来,复杂度降为$o(q\log n\cdot \alpha(n))$
实现中可能有一些细节问题:1.$nex[k].fi.fi$表示了左子树中小于等于它的最大数,若不存在则为最小的数,若没有数就随便(在query中要判断这个区间是否存在数,而且有可能因为删除而没有数),其余同理;2.每一个数要存储个数,否则会导致存在但无法找到;3.如果最小或最大的数删掉,并查集就指向不存在的位置来表示
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define N 1000005 4 #define mid (l+r>>1) 5 #define L (k<<1) 6 #define R (L+1) 7 #define mp make_pair 8 #define fi first 9 #define se second 10 #define oo 0x3f3f3f3f 11 struct ji{ 12 int p,l,r,k; 13 }q[N]; 14 vector<int>f[N<<1],tot[N<<1],fa[2][N<<1]; 15 vector<pair<pair<int,int>,pair<int,int> > >nex[N<<1]; 16 int n,m,x,y,ans[N],sz[N<<1],now[N<<1]; 17 int find(int p,int x,int k){ 18 if ((k==sz[x])||(k==fa[p][x][k]))return k; 19 return fa[p][x][k]=find(p,x,fa[p][x][k]); 20 } 21 void add(int k,int l,int r,int x,int y){ 22 now[k]++; 23 if (l==r){ 24 sz[k]=1; 25 f[k].push_back(y); 26 tot[k].push_back(1); 27 return; 28 } 29 if (x<=mid)add(L,l,mid,x,y); 30 else add(R,mid+1,r,x,y); 31 } 32 void merge(int k,int l,int r){ 33 if (l==r){ 34 if (!sz[k])return; 35 fa[0][k].push_back(0); 36 fa[1][k].push_back(0); 37 return; 38 } 39 merge(L,l,mid); 40 merge(R,mid+1,r); 41 for(int i=0,j=0;(i<sz[L])||(j<sz[R]);){ 42 fa[0][k].push_back(sz[k]); 43 fa[1][k].push_back(sz[k]++); 44 if ((i<sz[L])&&(j<sz[R])&&(f[L][i]==f[R][j])){ 45 nex[k].push_back(mp(mp(i,i),mp(j,j))); 46 f[k].push_back(f[L][i]); 47 tot[k].push_back(tot[L][i++]+tot[R][j++]); 48 continue; 49 } 50 if ((i<sz[L])&&((j==sz[R])||(f[L][i]<f[R][j]))){ 51 nex[k].push_back(mp(mp(i,i),mp(j-(j>0),j-((j>0)&&(j==sz[R]))))); 52 f[k].push_back(f[L][i]); 53 tot[k].push_back(tot[L][i++]); 54 } 55 else{ 56 nex[k].push_back(mp(mp(i-(i>0),i-((i>0)&&(i==sz[L]))),mp(j,j))); 57 f[k].push_back(f[R][j]); 58 tot[k].push_back(tot[R][j++]); 59 } 60 } 61 } 62 void del(int k,int l,int r,int x,int y){ 63 now[k]--; 64 if (--tot[k][y]==0){ 65 if (!y)fa[0][k][y]=sz[k]; 66 else fa[0][k][y]=fa[0][k][y-1]; 67 if (y==sz[k]-1)fa[1][k][y]=sz[k]; 68 else fa[1][k][y]=fa[1][k][y+1]; 69 } 70 if (l==r)return; 71 if (x<=mid)del(L,l,mid,x,nex[k][y].fi.fi); 72 else del(R,mid+1,r,x,nex[k][y].se.fi); 73 } 74 int query(int k,int l,int r,int x,int y,int z,int a,int b){ 75 if ((l>y)||(x>r)||(!now[k]))return oo; 76 if ((x<=l)&&(r<=y)){ 77 int ans=oo; 78 if (find(0,k,a)<sz[k])ans=min(ans,abs(z-f[k][find(0,k,a)])); 79 if (find(1,k,b)<sz[k])ans=min(ans,abs(z-f[k][find(1,k,b)])); 80 return ans; 81 } 82 return min(query(L,l,mid,x,y,z,nex[k][a].fi.fi,nex[k][b].fi.se),query(R,mid+1,r,x,y,z,nex[k][a].se.fi,nex[k][b].se.se)); 83 } 84 int main(){ 85 scanf("%d%d",&n,&m); 86 for(int i=1;i<=m;i++){ 87 scanf("%d%d",&q[i].p,&q[i].l); 88 if (q[i].p)scanf("%d%d",&q[i].r,&q[i].k); 89 else{ 90 scanf("%d",&q[i].k); 91 add(1,1,n,q[i].l,q[i].k); 92 } 93 } 94 merge(1,1,n); 95 for(int i=m;i;i--) 96 if (!q[i].p)del(1,1,n,q[i].l,lower_bound(f[1].begin(),f[1].end(),q[i].k)-f[1].begin()); 97 else{ 98 x=upper_bound(f[1].begin(),f[1].end(),q[i].k)-f[1].begin()-1; 99 y=lower_bound(f[1].begin(),f[1].end(),q[i].k)-f[1].begin(); 100 ans[++ans[0]]=query(1,1,n,q[i].l,q[i].r,q[i].k,max(x,0),y); 101 } 102 for(int i=ans[0];i;i--) 103 if (ans[i]==oo)printf("-1\n"); 104 else printf("%d\n",ans[i]); 105 }