 /**//*
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
搜索
最新評論

|
|