[BZOJ3932][CQOI2015]任务查询系统

[BZOJ3932][CQOI2015]任务查询系统

试题描述

最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行),其优先级为Pi。同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同。调度系统会经常向查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个)的优先级之和是多少。特别的,如果Ki大于第Xi秒正在运行的任务总数,则直接回答第Xi秒正在运行的任务优先级之和。上述所有参数均为整数,时间的范围在1到n之间(包含1和n)。

输入

输入文件第一行包含两个空格分开的正整数m和n,分别表示任务总数和时间范围。接下来m行,每行包含三个空格分开的正整数Si、Ei和Pi(Si≤Ei),描述一个任务。接下来n行,每行包含四个空格分开的整数Xi、Ai、Bi和Ci,描述一次查询。查询的参数Ki需要由公式 Ki=1+(Ai*Pre+Bi) mod Ci计算得到。其中Pre表示上一次查询的结果,对于第一次查询,Pre=1。

输出

输出共n行,每行一个整数,表示查询结果。

输入示例

4 3
1 2 6
2 3 3
1 3 2
3 3 4
3 1 3 2
1 1 3 4
2 2 4 3

输出示例

2
8
11

数据规模及约定

对于100%的数据,1≤m,n,Si,Ei,Ci≤100000,0≤Ai,Bi≤100000,1≤Pi≤10000000,Xi为1到n的一个排列

题解

如果知道扫描线的话这题就很水了。一个很套路的思想:每个任务是一个区间,我们可以把它拆成两个端点,左端点加右端点减,然后建立主席树就好了。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

const int BufferSize = 1 << 16;
char buffer[BufferSize], *Head, *Tail;
inline char Getchar() {
	if(Head == Tail) {
		int l = fread(buffer, 1, BufferSize, stdin);
		Tail = (Head = buffer) + l;
	}
	return *Head++;
}
int read() {
	int x = 0, f = 1; char c = Getchar();
	while(!isdigit(c)){ if(c == '-') f = -1; c = Getchar(); }
	while(isdigit(c)){ x = x * 10 + c - '0'; c = Getchar(); }
	return x * f;
}

#define LL long long
#define maxval 10000000
#define maxn 100010
#define maxnode 6666666

int ToT, rt[maxn], cntv[maxnode], lc[maxnode], rc[maxnode];
LL sumv[maxnode];
void update(int& y, int x, int l, int r, int p, int v) {
	cntv[y = ++ToT] = cntv[x] + v;
	sumv[y] = sumv[x] + (LL)v * p;
	if(l == r) return ;
	int mid = l + r >> 1; lc[y] = lc[x]; rc[y] = rc[x];
//	printf("%d bel [%d, %d]\n", p, l, r);
	if(p <= mid) update(lc[y], lc[x], l, mid, p, v);
	else update(rc[y], rc[x], mid + 1, r, p, v);
	return ;
}

LL solve(int time, int k) {
//	printf("solve(%d, %d)\n", time, k);
	LL ans = 0;
	int l = 1, r = maxval, Rt = rt[time];
	while(l < r) {
		int mid = l + r >> 1, sum = (Rt && lc[Rt]) ? cntv[lc[Rt]] : 0;
//		printf("[%d, %d]: %d\n", l, mid, sum);
		if(sum < k) {
			k -= sum; l = mid + 1; ans += (Rt && lc[Rt]) ? sumv[lc[Rt]] : 0;
			if(Rt) Rt = rc[Rt];
		}
		else {
			r = mid;
			if(Rt) Rt = lc[Rt];
		}
	}
//	printf("%d %d %d\n", l, ans, cntv[Rt]);
	return ans + (Rt ? (LL)min(cntv[Rt], k) * l : 0);
}

struct Point {
	int time, pri, tp;
	Point() {}
	Point(int _1, int _2, int _3): time(_1), pri(_2), tp(_3) {}
	bool operator < (const Point& t) const { return time < t.time; }
} ps[maxn<<1];
int cntp;

int main() {
	int m = read(), n = read();
	for(int i = 1; i <= m; i++) {
		int st = read(), en = read(), p = read();
		ps[++cntp] = Point(st, p, 1);
		ps[++cntp] = Point(en + 1, p, -1);
	}
	sort(ps + 1, ps + cntp + 1);
//	for(int i = 1; i <= cntp; i++) printf("%d %d %d\n", ps[i].time, ps[i].pri, ps[i].tp);
	for(int T = 1, i = 1; T <= n; T++) {
		rt[T] = rt[T-1];
		while(i <= cntp && ps[i].time == T)
			update(rt[T], rt[T], 1, maxval, ps[i].pri, ps[i].tp), i++;
	}
	LL lst = 1;
	for(int i = 1; i <= n; i++) {
		int time = read(); LL a = read(), b = read(), c = read();
		int k = 1 + (a * lst + b) % c;
		printf("%lld\n", lst = solve(time, k));
	}
	
	return 0;
}

 

posted @ 2017-01-29 10:41  xjr01  阅读(218)  评论(0编辑  收藏  举报