/**//* n<=10^9个位置, q<=10^5个操作 操作有三种 (1)插入 选择靠右的最长空白的一段,然后插入到中间(若长度为偶数,是指靠右的那个中间位置) (2)删除 (3)查询一段中的已插入点个数
我一开始想线段树,搞不出,主要是那些点不确定 看了shik的代码,神奇丫
树状数组的数组可以用map<int,int>来做,解决了空间问题!!! 用set<Segment>来存储可用的线段 然后需要再加多一个set记录所有分割点,这个很重要,我当时没想到这个#_#
然后就是维护上面3个主要的数据结构了 */ #include<iostream> #include<cstring> #include<map> #include<algorithm> #include<stack> #include<queue> #include<cmath> #include<string> #include<cstdlib> #include<vector> #include<cstdio> #include<set> #include<list> #include<numeric> #include<cassert> #include<ctime> #include<bitset>
using namespace std;
struct Segment { int st, ed; Segment(int st, int ed) : st(st), ed(ed){ } };
inline bool operator < (const Segment & A, const Segment &B) { if(A.ed - A.st != B.ed - B.st) { return A.ed - A.st > B.ed - B.st; } return A.st > B.st; }
map<int, int> C; int n, q;
inline int lowbit(int x) { return x & (-x); }
void insert(int x , int val) { while(x <= n) { C[x] += val; x += lowbit(x); } }
int query(int x) { map<int,int>::iterator it; int ans = 0; while(x > 0) { // ans += C[x]; 不要直接这样,需要先查找一下,不存在的不用加,快很多!!! if((it = C.find(x)) != C.end()){ ans += it->second; } x -= lowbit(x); } return ans; }
int query(int x, int y) { return query(y) - query(x-1); }
int main() { #ifndef ONLINE_JUDGE freopen("in","r",stdin); #endif for (; ~scanf("%d%d", &n, &q); ) { C.clear(); set<Segment> iset; iset.insert(Segment(1,n)); set<int> pt; pt.insert(0); pt.insert(n+1); map<int,int> mp;
int p, st, ed; while(q--) { scanf("%d", &p); if(p == 0) { scanf("%d%d", &st, &ed); printf("%d\n", query(st,ed)); } else { if(mp[p] == 0){ set<Segment>::iterator it = iset.begin(); st = it->st, ed = it->ed; iset.erase(it); int m = (st+ed+1) / 2; mp[p] = m; pt.insert(m); insert(m,1); if(st <= m - 1){ iset.insert(Segment(st,m-1)); } if(m+1 <= ed) { iset.insert(Segment(m+1,ed)); } } else { int m = mp[p]; mp[p] = 0; set<int>::iterator left, right, it; /**//* left = pt.lower_bound(m); left--; right = pt.upper_bound(m); pt.erase(m); */ left = right = it = pt.find(m); left --; right++; pt.erase(it); insert(m,-1); st = (*left)+1; ed = (*right)-1; if(st <= m - 1) { iset.erase(Segment(st, m-1)); } if(m+1 <= ed) { iset.erase(Segment(m+1,ed)); } if(st <= ed){ iset.insert(Segment(st,ed)); } } } } } return 0; }
|
|
常用链接
随笔分类
Links
搜索
最新评论
|
|