问题 C: 玫瑰花精
时间限制: 1 Sec 内存限制: 256 MB
题面
题面谢绝公开。
题解
线段树记录四个信息:l、r、mid、p。
l代表线段树该节点所管辖的区间内最左边的花精所在位置。r代表最右边花精所在位置。
mid代表区间内相邻花精距离最大值除以二,p代表mid值所在的位置。
考虑初始值:
对于每一个线段树所管辖的每一个区间,$l=r=0$。$mid=p=0$。
考虑转移过程:
l取最左边,若左儿子的l有值,则为左儿子的l,否则若右儿子的l有值,l取右儿子的l,否则为0。r同理。
mid先在左儿子的mid和右儿子的mid中取最大值,然后考虑跨区间的转移。
若左儿子的r!=0,右儿子的l!=0,则mid=max(mid,(右儿子的l-左儿子的r)/2)。p相应更新。
至于第一个花精进入判掉即可233。
代码:
#include<bits/stdc++.h> #define rint register int #define lc(A) (A<<1) #define rc(A) (A<<1|1) using namespace std; int n,m,vis[1000006]; struct node{int l,r,mid,p;}t[1000006<<5]; inline int get_dis() { if(t[1].l==0)return 1; // cout<<t[1].l-1<<' '<<n-t[1].r<<' '<<t[1].mid<<endl; int lin=max(max(t[1].l-1,n-t[1].r),t[1].mid); if(lin==t[1].l-1)return 1; else if(lin==t[1].mid)return t[1].p; else return n; } inline void update(int k) { t[k].l=(t[lc(k)].l)?t[lc(k)].l:t[rc(k)].l; t[k].r=(t[rc(k)].r)?t[rc(k)].r:t[lc(k)].r; t[k].mid=max(t[lc(k)].mid,t[rc(k)].mid); int lin_l=t[lc(k)].r,lin_r=t[rc(k)].l; if(lin_l&&lin_r)t[k].mid=max(t[k].mid,(lin_r-lin_l)>>1); if(t[k].mid==t[lc(k)].mid)t[k].p=t[lc(k)].p; else if(t[k].mid==(lin_r-lin_l)>>1)t[k].p=(lin_l+lin_r)>>1; else t[k].p=t[rc(k)].p; return ; } inline void add(int k,int l,int r,int p) { if(l==r) { t[k].l=t[k].r=l; t[k].p=t[k].mid=0; return ; } int mid=(l+r)>>1; if(p<=mid)add(lc(k),l,mid,p); else add(rc(k),mid+1,r,p); update(k); } inline void del(int k,int l,int r,int p) { if(l==r) { t[k].l=t[k].r=0; t[k].p=t[k].mid=0; return ; } int mid=(l+r)>>1; if(p<=mid)del(lc(k),l,mid,p); else del(rc(k),mid+1,r,p); update(k); } int main() { scanf("%d %d",&n,&m); for(rint i=1,cz,x;i<=m;++i) { scanf("%d %d",&cz,&x); if(cz==1) { vis[x]=get_dis(); add(1,1,n,vis[x]); printf("%d ",vis[x]); } else del(1,1,n,vis[x]); } return 0; } /* 7 11 1 15 1 123123 1 3 1 5 2 123123 2 15 1 21 2 3 1 6 1 7 1 8 */