在爱神博客找到的题, 思路很巧妙, 用链表把所有的盒子顺序连起来,然后在每次burst后维护维护链表
如果盒子内的气球数不为0,则答案显然不会增加,直接输出上次答案,继续
如果在burst后盒子i内的气球为0, 则增加的答案数为左端点在(L[i], i], 右端点在[i, R[i])的pair数目,然后删除这个节点(令L[R[i]] = L[i], R[L[i]] = L[i]) ,由于节点i至多被删除一次,所以每个pair至多被统计一次。
问题的关键就在如何快速查询左端点在(L[i], i], 右端点在[i, R[i])的pair数目, 可以用二维数据结构,但是内存和效率都不理想。函数式线段树可以实现这个功能,按照左端点顺序建树,用线段树维护右端点的数目。
最近在做函数式数据结构的题目,发现函数式数据结构解决的都是一些二维限制的询问,先通过持久化解决掉一维,然后用线段树维护另外一维,对哪一维进行持久化是解题的关键。以上为个人拙见,神牛请无视。
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <queue> #include <algorithm> #include <vector> #include <cstring> #include <stack> #include <cctype> #include <utility> #include <map> #include <string> #include <climits> #include <set> #include <string> #include <sstream> #include <utility> #include <ctime> #include <bitset> //#pragma comment(linker, "/STACK:102400000,102400000") using std::priority_queue; using std::vector; using std::swap; using std::stack; using std::sort; using std::max; using std::min; using std::pair; using std::map; using std::string; using std::cin; using std::cout; using std::set; using std::queue; using std::string; using std::stringstream; using std::make_pair; using std::getline; using std::greater; using std::endl; using std::multimap; using std::deque; using std::unique; using std::lower_bound; using std::random_shuffle; using std::bitset; using std::upper_bound; using std::multiset; typedef long long LL; typedef unsigned long long ULL; typedef unsigned UN; typedef pair<int, int> PAIR; typedef multimap<int, int> MMAP; typedef LL TY; typedef long double LF; const int MAXN(1800010); const int MAXM(50010); const int MAXE(150010); const int MAXK(6); const int HSIZE(13131); const int SIGMA_SIZE(4); const int MAXH(20); const int INFI((INT_MAX-1) >> 1); const ULL BASE(31); const LL LIM(1e13); const int INV(-10000); const int MOD(31313); const double EPS(1e-7); const LF PI(acos(-1.0)); template<typename T> inline void checkmax(T &a, T b){if(b > a) a = b;} template<typename T> inline void checkmin(T &a, T b){if(b < a) a = b;} template<typename T> inline T ABS(const T &a){return a < 0? -a: a;} int ls[MAXN], rs[MAXN], sum[MAXN], rear; int root[100010]; void updata(int l, int r, int val, int prt, int &rt) { rt = rear++; ls[rt] = ls[prt]; rs[rt] = rs[prt]; sum[rt] = sum[prt]+1; if(l == r) return; int m = (l+r) >> 1; if(val <= m) updata(l, m, val, ls[prt], ls[rt]); else updata(m+1, r, val, rs[prt], rs[rt]); } int query(int l, int r, int ql, int qr, int rt) { if(ql <= l && qr >= r) return sum[rt]; int m = (l+r) >> 1, ret = 0; if(ql <= m) ret = query(l, m, ql, qr, ls[rt]); if(qr > m) ret += query(m+1, r, ql, qr, rs[rt]); return ret; } int L[100010], R[100010], quant[100010]; struct ELE { int l, r; friend bool operator < (const ELE &a, const ELE &b){ return a.l < b.l;} } ele[100010]; int main() { int n, m; while(~scanf("%d%d", &n, &m)) { for(int i = 1; i <= n; ++i) { scanf("%d", quant+i); L[i] = i-1; R[i] = i+1; } R[0] = 1; L[n+1] = n; for(int i = 0; i < m; ++i) scanf("%d%d", &ele[i].l, &ele[i].r); sort(ele, ele+m); root[0] = 0; ls[0] = rs[0] = 0; sum[0] = 0; rear = 1; int ind = 0; for(int i = 1; i <= n; ++i) { root[i] = root[i-1]; while(ind < m && ele[ind].l == i) updata(1, n, ele[ind++].r, root[i], root[i]); } int K, temp, ans = 0; scanf("%d", &K); for(int i = 0; i < K; ++i) { scanf("%d", &temp); temp += ans; if(quant[temp] == 0) { printf("%d\n", ans); continue; } --quant[temp]; if(quant[temp] == 0) { ans += query(1, n, temp, R[temp]-1, root[temp])-query(1, n, temp, R[temp]-1, root[L[temp]]); L[R[temp]] = L[temp]; R[L[temp]] = R[temp]; } printf("%d\n", ans); } } return 0; }