题目是个队列问题,涉及到进队,出队,查询三种操作
- t d ,表示在时刻 t 某个骑士来访,需要和国王交谈 d 的时间。(进队)
− i ,表示撤销第 i 次操作,第i次请求来访的骑士突然变卦,取消了访问请求。(出队)
? t ,表示询问公主在时刻 t 请求访问国王,她需要等多久才能轮到她。
注意到时间值域是 [1,1e6] ,考虑使用权值线段树维护这个队列。线段树上的一个点代表一个时间段,前两个操作对应线段树的单点修改,第三个操作对应线段树的区间查询。具体维护的信息见代码注释。
#include<bits/stdc++.h>
#define Accepted 0
using Azir = int;
namespace fastIO {
#define BUF_SIZE 100000
#define DECIMAL 6
#define LL long long
bool IOerror = 0;
inline char nc() { static char buf[BUF_SIZE], * p1 = buf + BUF_SIZE, * pend = buf + BUF_SIZE; if (p1 == pend) { p1 = buf; pend = buf + fread(buf, 1, BUF_SIZE, stdin); if (pend == p1) { IOerror = 1; return -1; } }return *p1++; }
inline bool blank(char ch) { return ch == ' ' || ch == '\n' || ch == '\r' || ch == '\t'; }
template<class T> inline bool read(T& x) { bool sign = 0; char ch = nc(); x = 0; for (; blank(ch); ch = nc()); if (IOerror)return false; if (ch == '-')sign = 1, ch = nc(); for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0'; if (sign)x = -x; return true; }
inline bool read(unsigned long long& x) { char ch = nc(); x = 0; for (; blank(ch); ch = nc()); if (IOerror)return false; for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0'; return true; }
inline bool read(unsigned int& x) { char ch = nc(); x = 0; for (; blank(ch); ch = nc()); if (IOerror)return false; for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0'; return true; }
inline bool read(double& x) { bool sign = 0; char ch = nc(); x = 0; for (; blank(ch); ch = nc()); if (IOerror)return false; if (ch == '-')sign = 1, ch = nc(); for (; ch >= '0' && ch <= '9'; ch = nc())x = x * 10 + ch - '0'; if (ch == '.') { double tmp = 1; ch = nc(); for (; ch >= '0' && ch <= '9'; ch = nc())tmp /= 10.0, x += tmp * (ch - '0'); }if (sign)x = -x; return true; }
inline bool read(char* s) { char ch = nc(); for (; blank(ch); ch = nc()); if (IOerror)return false; for (; !blank(ch) && !IOerror; ch = nc())*s++ = ch; *s = 0; return true; }
inline bool read(char& c) { for (c = nc(); blank(c); c = nc()); if (IOerror) { c = -1; return false; }return true; }
inline bool read(std::string& s) { s.clear(); char ch = nc(); for (; blank(ch); ch = nc()); if (IOerror)return false; for (; !blank(ch) && !IOerror; ch = nc())s += ch; return true; }
template<class T, class... U>bool read(T& h, U&... t) { return read(h) && read(t...); }
struct Ostream_fwrite {
char* buf, * p1, * pend;
Ostream_fwrite() { buf = new char[BUF_SIZE]; p1 = buf; pend = buf + BUF_SIZE; }
inline void out(char ch) { if (p1 == pend) { fwrite(buf, 1, BUF_SIZE, stdout); p1 = buf; }*p1++ = ch; }
template<class T>inline void print(T x) { static char s[41], * s1; s1 = s; if (!x)*s1++ = '0'; if (x < 0)out('-'), x = -x; while (x)*s1++ = x % 10 + '0', x /= 10; while (s1-- != s)out(*s1); }
inline void print(char ch) { out(ch); }
inline void print(unsigned long long x) { static char s[41], * s1; s1 = s; if (!x)*s1++ = '0'; while (x)*s1++ = x % 10 + '0', x /= 10; while (s1-- != s)out(*s1); }
inline void print(unsigned int x) { static char s[41], * s1; s1 = s; if (!x)*s1++ = '0'; while (x)*s1++ = x % 10 + '0', x /= 10; while (s1-- != s)out(*s1); }
inline void print(double x, int y = DECIMAL) {
static LL mul[] = { 1,10,100,1000,10000,100000,1000000,10000000,100000000,
1000000000,10000000000LL,100000000000LL,1000000000000LL,10000000000000LL,
100000000000000LL,1000000000000000LL,10000000000000000LL,100000000000000000LL };
if (x < -1e-12)out('-'), x = -x; x *= mul[y];
LL x1 = (LL)floor(x); if (x - floor(x) >= 0.5)++x1;
LL x2 = x1 / mul[y], x3 = x1 - x2 * mul[y]; print(x2);
if (y > 0) { out('.'); for (size_t i = 1; i < y && x3 * mul[i] < mul[y]; out('0'), ++i); print(x3); }
}
inline void print(char* s) { while (*s)out(*s++); }
inline void print(const char* s) { while (*s)out(*s++); }
inline void print(std::string s) { print(s.c_str()); }
inline void flush() { if (p1 != buf) { fwrite(buf, 1, p1 - buf, stdout); p1 = buf; } }
~Ostream_fwrite() { flush(); }
}Ostream;
template<class T>inline void print(T x) { Ostream.print(x); }
template<class T>inline void println(T x) { Ostream.print(x); Ostream.out('\n'); }
inline void print(double x, int y = DECIMAL) { Ostream.print(x, y); }
inline void println(double x, int y = DECIMAL) { Ostream.print(x, y); Ostream.out('\n');; }
template<class T, class... U>void print(const T& h, const U&... t) { print(h); Ostream.out(' ');; print(t...); }
template<class T, class... U>void println(const T& h, const U&... t) { print(h); Ostream.out(' ');; println(t...); }
inline void flush() { Ostream.flush(); }
// C int,long long ,__int128,unsigned long long,unsigned int,double,char[],char
// c++ string
#undef LL
#undef DECIMAL
#undef BUF_SIZE
};
using namespace fastIO;
typedef long long LL;
using namespace std;
const int32_t MAXN = 1e6 + 5;
struct node
{
LL sum;//在该区间内时间点来访问的骑士 的谈话时间总和
LL ending;//结束 所有在该区间内时间点 来访的骑士 谈话 的 时间
bool empty;//是否有效
node(bool f = false) {
sum = 0;
empty = f;
}
}d[MAXN << 2];
node operator +(const node& a, const node& b)//重载 + 运算符 ,对应了 左右两个区间的合并方式
{
//a 左区间 b 右区间
//c 由 左右子区间 合并而成的区间
node c;
if (a.empty)return b;//某一个为空 直接返回另外一个 //不作合并
if (b.empty)return a;
c.ending = max(a.ending + b.sum, b.ending);//这里是核心 左区间的最终完成时间+右区间的总交谈时间 和 右区间的最终完成时间 取max
//对于取max,举个例子会比较容易理解
//比如说 线段树上该点代表的 是 [4,8] 这个时间段 ,会出现两种 情况
// 1 :假设有一个骑士 在 时刻5 来访,需要交谈 2个时刻 ,那么他和国王的谈话在时刻 7 结束
// 然而这个区间的ending并不是7,它本身就是[4,8] ,当然是在时刻8 结束了 ,也就是 max(7,8) 保证了正确的ending 不妨认为这是个较为空闲的时间段,ending即本身时间段的ending
// 2 : 假设有一个骑士 在 时刻5 来访,需要交谈 10个时刻,那么他和国王的谈话在时刻 15 结束
// 此时这个区间的ending就是15,它超出了 原本的[4,8],还多占用了 7个时刻 ,也就是 max(15,8) 不妨认为这是个繁忙的时间段,繁忙到不得不占用后面时间段的时间。
c.sum = a.sum + b.sum;
return c;
}
LL a[MAXN];
#define lson rt<<1
#define rson rt<<1|1
inline void push_up(int rt)
{
d[rt] = d[lson] + d[rson];
}
void build(int l, int r, int rt)
{
if (l == r)
{
d[rt].sum = 0;
d[rt].ending = l;
return;
}
int mid = (l + r) >> 1;
build(l, mid, lson);
build(mid + 1, r, rson);
push_up(rt);
}
void modify(int x, LL c, int l, int r, int rt)
{
if (l == r) {
d[rt].sum += c;
d[rt].ending += c;
return;
}
int mid = (l + r) >> 1;
if (x <= mid)modify(x, c, l, mid, lson);
if (x >= mid + 1)modify(x, c, mid + 1, r, rson);
push_up(rt);
}
node query(int L, int R, int l, int r, int rt)
{
node res(true);// res置为空,只起到连接作用,不参与 +号运算
if (L <= l && r <= R)
{
return d[rt];
}
int mid = (l + r) >> 1;
if (L <= mid) res = res + query(L, R, l, mid, lson);
if (R >= mid + 1)res = res + query(L, R, mid + 1, r, rson);
return res;
}
int p[MAXN];
LL v[MAXN];
Azir main()
{
#ifdef DEBUG
freopen("..\\DEBUG\\IO\\1.in", "r", stdin);
// freopen("my.out", "w", stdout);
clock_t c1 = clock();
#endif
int n;
read(n);
int MAXT = 1e6;
build(1, MAXT, 1);
for (int i = 1; i <= n; i++)
{
char op;
int x; LL y;
read(op);
if (op == '+') {
read(x, y);
modify(x, y, 1, MAXT, 1);
p[i] = x;
v[i] = y;
}
else if (op == '-')
{
read(x);
modify(p[x], -v[x], 1, MAXT, 1);
}
else
{
read(x);
println(query(1, x, 1, MAXT, 1).ending - x);
//注意求的是公主的等待时间,而线段树上维护的是全局等待时间,所以要减去公主来的时间点 x
}
}
fastIO::flush();
#ifdef DEBUG
std::cerr << "Time:" << clock() - c1 << "ms" << std::endl;
#endif
return Accepted;
}
/// .-~~~~~~~~~-._ _.-~~~~~~~~~-.
/// __.' ~. .~ `.__
/// .'// \./ \\`.
/// .'// | \\`.
/// .'// .-~"""""""~~~~-._ | _,-~~~~"""""""~-. \\`.
/// .'//.-" `-. | .-' "-.\\`.
/// .'//______.============-.. \ | / ..-============.______\\`.
/// .'______________________________\|/______________________________`.