NEERC2018 K. King Kog’s Reception
题目链接
http://codeforces.com/contest/1089/problem/K
题目大意
国王给前来拜访的骑士设计了一个队列。如果他们到的时候队列里面有其他人,那么他就会排在后面,否则会直接去拜访。有 $q$ 次询问,操作一为在 $t$ 时刻加入一个拜访时间为 $d$ 的骑士。操作二为删除一个骑士。操作三为询问如果公主 $t$ 时刻来,那么她需要等多长时间才能拜访到国王。
题目分析
这道题很明显是一道数据结构题。
首先考虑,需要知道什么信息,使得 $[l, mid]$ 和 $(mid, r]$ 的区间可以合并并能获取到有用的信息。对题目有直接帮助的显然是区间的结束时间。那么考虑到合并区间的问题,显然还需要记录每个区间的开始时间,还有中间空白的区域。那么如果前面区间等待的时间已经影响到后面的区间,首先会占用后面区间中的空白区域,都占用完了之后,才会推迟最终结束时间。如此一来,可以使用线段树或者平衡树维护即可。
训练赛时队友使用的是线段树,以下代码为赛后重写的平衡树版本。
代码
#include <iostream> #include <cstdio> #include <cstdlib> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <ctime> using namespace std; const int maxn = 3e5 + 5; int n, m, q; int opt[maxn]; struct ex { long long st; long long ed; long long blank; int init(long long t, long long d){ st = t; ed = t + d; blank = 0; return 0; } }; ex exmerge(ex x, ex y){ ex ret; if(x.st == 0){ return y; } if(y.st == 0){ return x; } if(x.ed < y.st){ ret.st = x.st; ret.ed = y.ed; ret.blank = x.blank + y.blank + y.st - x.ed; }else{ ret.st = x.st; ret.ed = y.ed + max(x.ed - y.st - y.blank, 0ll); ret.blank = x.blank + y.blank - min(x.ed - y.st, y.blank); } return ret; } struct node { long long t; long long d; ex x; int fix; int c[2]; int init(long long tt, long long dd){ t = tt; d = dd; fix = rand(); c[0] = c[1] = 0; x.init(tt, dd); return 0; } }; node tree[maxn * 2]; int tc = 0; int root = 0; int read(){ int x; scanf("%d", &x); return x; } int merge(int pos){ tree[pos].x.init(tree[pos].t, tree[pos].d); if(tree[pos].c[0]){ tree[pos].x = exmerge(tree[tree[pos].c[0]].x, tree[pos].x); } if(tree[pos].c[1]){ tree[pos].x = exmerge(tree[pos].x, tree[tree[pos].c[1]].x); } return 0; } int rotate(int &pos, int d){ int c = tree[pos].c[d]; tree[pos].c[d] = tree[c].c[!d]; tree[c].c[!d] = pos; merge(pos); merge(c); pos = c; return 0; } int insert(int &pos, long long t, long long d){ if(!pos){ pos = ++tc; tree[pos].init(t, d); }else{ int dr = tree[pos].t < t; insert(tree[pos].c[dr], t, d); if(tree[pos].fix < tree[tree[pos].c[dr]].fix){ rotate(pos, dr); } merge(pos); } return 0; } int remove(int &pos, long long t){ if(tree[pos].t != t){ int d = tree[pos].t < t; remove(tree[pos].c[d], t); merge(pos); }else{ if(!tree[pos].c[0]){ pos = tree[pos].c[1]; }else if(!tree[pos].c[1]){ pos = tree[pos].c[0]; }else{ int d = tree[tree[pos].c[0]].fix < tree[tree[pos].c[1]].fix; rotate(pos, d); remove(tree[pos].c[!d], t); merge(pos); } } return 0; } ex query(int &pos, long long t){ ex ret; if(!pos){ ret.init(0, 0); }else{ ret.init(tree[pos].t, tree[pos].d); if(tree[pos].t > t){ ret = query(tree[pos].c[0], t); }else if(tree[pos].t == t){ ret = exmerge(tree[tree[pos].c[0]].x, ret); }else{ ret = exmerge(exmerge(tree[tree[pos].c[0]].x, ret), query(tree[pos].c[1], t)); } } return ret; } long long getans(long long t){ ex ret = query(root, t); return max(ret.ed - t, 0ll); } int main(){ int i, j; char op; int x, y; srand(time(0)); q = read(); for(i=1;i<=q;i++){ scanf(" %c", &op); if(op == '+'){ x = read(); y = read(); opt[i] = x; insert(root, x, y); }else if(op == '-'){ x = read(); remove(root, opt[x]); }else{ x = read(); printf("%lld\n", getans(x)); } } return 0; }