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