线段树 离散区间,单点维护区间
这道题当时用线段树搞不行,用主席树搞,也不行。当场自闭。。。
其实当时想到离散,但是没想到用单点维护线段树的区间。。。。。。
你这样想,无非就是2e6次询问,最多1-e9被分成最多2e6区间,我们要求的位置,一定在这2e6点的右边第一个。
那么把这个点,以及这个点x以及x+1的点保存下来。
维护的时候,线段树初始化所有的单点值为1,并维护区间和,代表单点没有被删掉。
我们优先往左查询,并保证不越过区间之外,如果查询到满足条件的,我们不再往后继续查询,否则往右查询。
#include<iostream> #include<stdio.h> #include<string.h> #include<algorithm> #include<bits/stdc++.h> #define LL long long #define lson rt<<1 #define rson rt<<1|1 using namespace std; const int maxx = 2e6+6; struct node{ int l,r; int cnt; }tree[maxx<<2]; int op[maxx],pos[maxx]; vector<int>p; int cnt,ans; int get_pos(int x){ return lower_bound(p.begin(),p.end(),x)-p.begin()+1; } void buildtree(int rt,int l,int r){ tree[rt].l=l; tree[rt].r=r; if (l==r){ tree[rt].cnt=r-l+1; return ; } int mid=(l+r)>>1; buildtree(lson,l,mid); buildtree(rson,mid+1,r); tree[rt].cnt=tree[lson].cnt+tree[rson].cnt; } void update(int rt,int pos){ int l=tree[rt].l; int r=tree[rt].r; if (l==r){ tree[rt].cnt=0; return ; } int mid=(l+r)>>1; if (pos<=mid){ update(lson,pos); }else{ update(rson,pos); } tree[rt].cnt=tree[lson].cnt+tree[rson].cnt; } int flag=0; void query(int rt,int ql,int qr){ int l=tree[rt].l; int r=tree[rt].r; if(l==r){ if(tree[rt].cnt){ // cout<<l<<" "<<r<<endl; flag=1; ans=p[l-1]; } return ; } int mid=(l+r)>>1; if (!flag && ql<=mid && tree[lson].cnt){ ///如果当前没有查到,并且左儿子的区间和询问区间有交集,并且左儿子区间有没有被消除的点 ///这里注意,左区间和不为0不代表一定有,因为我们不知道左区间和询问区间的交集是否有 query(lson,ql,qr); } if (!flag && tree[rson].cnt){ query(rson,ql,qr); } } int main(){ int n,q; while(~scanf("%d%d",&n,&q)){ cnt=0; for(int i=1;i<=q;i++){ scanf("%d%d",&op[i],&pos[i]); p.push_back(pos[i]); p.push_back(pos[i]+1); } sort(p.begin(),p.end()); p.erase(unique(p.begin(),p.end()),p.end()); int sz=p.size(); buildtree(1,1,sz); for (int i=1;i<=q;i++){ if (op[i]==1){ update(1,get_pos(pos[i])); }else{ flag=0; query(1,get_pos(pos[i]),sz); printf("%d\n",ans); } } } return 0; }
有不懂欢迎咨询
QQ:1326487164(添加时记得备注)