http://www.lydsy.com/JudgeOnline/problem.php?id=3932
Description
最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的
任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行
),其优先级为Pi。同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同。调度系统会经常向
查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个
)的优先级之和是多少。特别的,如果Ki大于第Xi秒正在运行的任务总数,则直接回答第Xi秒正在运行的任务优先
级之和。上述所有参数均为整数,时间的范围在1到n之间(包含1和n)。
Input
输入文件第一行包含两个空格分开的正整数m和n,分别表示任务总数和时间范围。接下来m行,每行包含三个空格
分开的正整数Si、Ei和Pi(Si≤Ei),描述一个任务。接下来n行,每行包含四个空格分开的整数Xi、Ai、Bi和Ci,
描述一次查询。查询的参数Ki需要由公式 Ki=1+(Ai*Pre+Bi) mod Ci计算得到。其中Pre表示上一次查询的结果,
对于第一次查询,Pre=1。
Output
输出共n行,每行一个整数,表示查询结果。
首先把优先级离散化,然后用差分数组的思想,更新到主席树上去,主席树维护两个值,管辖区间的区间和与管辖区间内元素个数。
#include
using namespace std;
typedef long long ll;
const int N = 100000 + 10, INF = 0x3f3f3f3f;
struct node
{
int x, tp, p, v;
}a[N*2];
int lson[N*50], rson[N*50], siz[N*50];
ll sum[N*50];
int root[N];
int b[N], c[N], d[N];
int tot;
bool _cmp_(int x, int y)
{
return d[x] < d[y];
}
bool cmp(node a, node b)
{
return a.x < b.x;
}
void update(int &x, int last, int l, int r, int val, int v1, int v2)
{
x = ++tot;
lson[x] = lson[last], rson[x] = rson[last], sum[x] = sum[last]+v1, siz[x] = siz[last]+v2;
if(l == r) return;
int mid = (l + r) >> 1;
if(val <= mid) update(lson[x], lson[last], l, mid, val, v1, v2);
else update(rson[x], rson[last], mid+1, r, val, v1, v2);
}
ll query(int x, int l, int r, int k)
{
if(l == r) return sum[x];
int mid = (l + r) >> 1;
if(k <= siz[lson[x]]) return query(lson[x], l, mid, k);
else return sum[lson[x]] + query(rson[x], mid+1, r, k - siz[lson[x]]);
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
int x, y, z, num = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d%d%d", &x, &y, &z);
b[i] = i, d[i] = z;
a[++num].x = x, a[num].p = z, a[num].v = 1;
a[++num].x = y+1, a[num].p = -z, a[num].v = -1;
}
//这份代码对离散化有要求,要求离散化后相同的值不一样,即离散化结果为1~n,否则会出错
sort(b + 1, b + 1 + n, _cmp_);
for(int i = 1; i <= n; i++) c[b[i]] = i;
num = 0;
for(int i = 1; i <= n; i++) a[++num].tp = c[i], a[++num].tp = c[i];
sort(a + 1, a + 1 + num, cmp);
int j = 1;
for(int i = 1; i <= m; i++)
{
root[i] = root[i-1];
while(a[j].x == i) update(root[i], root[i], 1, n, a[j].tp, a[j].p, a[j].v), j++;
}
ll ans = 1;
for(int i = 1; i <= m; i++)
{
int x, a, b, c;
scanf("%d%d%d%d", &x, &a, &b, &c);
int k = 1 + (a * ans + b) % c;
ans = query(root[x], 1, n, k);
printf("%lld\n", ans);
}
return 0;
}
另外一种写法,首先也是离散化优先级,主席树只维护所管辖区间的元素个数,查询的时候,一直查询到叶节点
#include
using namespace std;
typedef long long ll;
const int N = 100000 + 10, INF = 0x3f3f3f3f;
struct node
{
int x, tp, p, v;
}a[N*2];
int lson[N*50], rson[N*50], siz[N*50];
int root[N];
int b[N], c[N], d[N];
int tot;
bool cmp(node a, node b)
{
return a.x < b.x;
}
void update(int &x, int last, int l, int r, int val, int v)
{
x = ++tot;
lson[x] = lson[last], rson[x] = rson[last], siz[x] = siz[last]+v;
if(l == r) return;
int mid = (l + r) >> 1;
if(val <= mid) update(lson[x], lson[last], l, mid, val, v);
else update(rson[x], rson[last], mid+1, r, val, v);
}
ll query(int x, int l, int r, int k)
{
if(k > siz[x]) k = siz[x];
if(l == r) return 1LL * k * b[l];
int mid = (l + r) >> 1;
if(k <= siz[lson[x]]) return query(lson[x], l, mid, k);
else return query(lson[x], l, mid, siz[lson[x]]) + query(rson[x], mid+1, r, k - siz[lson[x]]);
}
int main()
{
int n, m;
scanf("%d%d", &n, &m);
int x, y, z, num = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d%d%d", &x, &y, &z);
b[i] = z;
a[++num].x = x, a[num].p = z, a[num].v = 1;
a[++num].x = y+1, a[num].p = -z, a[num].v = -1;
}
sort(b + 1, b + 1 + n);
int len = unique(b + 1, b + 1 + n) - b - 1;
for(int i = 1; i <= num; i += 2)
{
a[i].tp = lower_bound(b + 1, b + 1 + len, a[i].p) - b;
a[i+1].tp = a[i].tp;
}
sort(a + 1, a + 1 + num, cmp);
int j = 1;
for(int i = 1; i <= m; i++)
{
root[i] = root[i-1];
while(a[j].x == i) update(root[i], root[i], 1, len, a[j].tp, a[j].v), j++;
}
ll ans = 1;
for(int i = 1; i <= m; i++)
{
int x, a, b, c;
scanf("%d%d%d%d", &x, &a, &b, &c);
int k = 1 + (a * ans + b) % c;
ans = query(root[x], 1, len, k);
printf("%lld\n", ans);
}
return 0;
}