NEERC2018 K. King Kog’s Reception

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;
}

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注

此站点使用Akismet来减少垃圾评论。了解我们如何处理您的评论数据