任务查询系统
题目描述
最近实验室正在为其管理的超级计算机编制一套任务管理系统,你被安排完成其中的查询部分。超级计算机中的任务用三元组(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
说明
样例解释
K1 = (1*1+3)%2+1 = 1
K2 = (1*2+3)%4+1 = 2
K3 = (2*8+4)%3+1 = 3
对于100%的数据,1≤m,n,Si,Ei,Ci≤100000,0≤Ai,Bi≤100000,1≤Pi≤10000000,Xi为1到n的一个排列
我的题解
这万恶的任务查询系统要询问任何时刻的前k小优先度之和。显然,任何时刻(可持久化)的前k小优先度之和(线段树)。
我们自然希望有这样一种东西就好了:对于任意的时刻,都有一棵线段树。这棵线段树维护的是当前时刻,任何一个优先度区间[l,r]中所在进行的任务数量的和以及它们优先度的和。然后我们在这棵线段树上找前k小的任务,把他们的优先度之和加起来(线段树的基本作用,求和),就可以了。同时我们还会发现这种线段树是可加减的。
对于每个时间都造一棵线段树显然会空间爆炸。于是我们构造可持久化线段树。
既然是可加减的,那么构造时就和差分数组类似。对于每一个任务,如果它的时间是t1~t2,优先度为f,我们就在原线段树的基础上,构造两棵新线段树。构造一个t1时刻的线段树,只需要在原来线段树的基础上将[f,f]这个区间的任务数+1,优先度之和+f;再构造t2+1时刻的线段树,在原来线段树的基础上将[f,f]这个区间的任务数-1,优先度之和-f。(具体的可持久化线段树写法,我的和大家的好像不太一样,但是应该还好懂)。
然后我们离散一下时间(这里的离散化是我在网上学的,挺巧妙,但是我找不到是哪位大神的博客了)。对于访问的任何一个时刻t,若满足t1<=t< t2,则认为访问的是t1的那棵线段树。当然,实际上还会有t3,t4之类,但只要是对于一段没有任何修改的时间中的任何时刻,都认为和这段时间的开始时刻是等效的。这样询问操作也解决了。
附上代码。
写的是数组线段树。
L[i]表示i节点的左儿子节点编号。
s[i]表示i节点为根的这棵线段树中所有的任务数量。
SS[i]表示优先度之和。
T[i]是第i棵线段树的根,对应的是离散后的每一个时刻。
to[i]就是刚才说的时间离散,对于任何时刻t(t1<=t< t2),to[t]=t1。
#include<cstdio>
#include<queue>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
#include<iostream>
#include<cstdlib>
#define mid (l+r)/2
using namespace std;
inline int read(){
char c;int ret=0;
do{c=getchar();}while(c>'9'||c<'0');
do{ret=ret*10+c-48;c=getchar();}while(c>='0'&&c<='9');
return ret;
}
int a,b,c;
long long pre=1;
int T[1000010],to[1000010];
int L[11000000],R[11000000];
long long SS[11000000];
int s[11000000];
int n,m;
struct E{
int pos,v;
};
E e[1000000];
bool cmp(E xxx,E yyy){
return xxx.pos<yyy.pos;
}
int cnt=0;
int maxx=0;
int cntt=0;
inline int aabbsss(int x){return x>0?x:-x;}
int update(int pr,int l,int r,int x){
int ret;
ret=++cntt;
L[ret]=L[pr];
R[ret]=R[pr];
if(x>0)s[ret]=s[pr]+1;
else s[ret]=s[pr]-1;
SS[ret]=SS[pr]+x;
if(l<r)
{
int v=aabbsss(x);
if(v<=mid) L[ret]=update(L[pr],l,mid,x);
else R[ret]=update(R[pr],mid+1,r,x);
}
return ret;
}
long long query(int u,int l,int r,int k){
long long ret=0;
if(s[u]<=k)return SS[u];
if(l==r)
{
if(s[u]==0)return 0;
if(s[u]<=k)return SS[u];
else return (SS[u]/s[u])*k;
}
if(k<=s[L[u]])
return query(L[u],l,mid,k);
else
{
ret+=SS[L[u]];
ret+=query(R[u],mid+1,r,k-s[L[u]]);
return ret;
}
}
int main(){
m=read();n=read();
int x,y,z;
for(int i=1;i<=m;i++)
{
x=read();y=read();z=read();
e[++cnt].pos=x;e[cnt].v=z;
e[++cnt].pos=y+1;e[cnt].v=-z;
maxx=max(maxx,z);
}
sort(e+1,e+cnt+1,cmp);
for(int i=1;i<=cnt;i++)
{
T[i]=update(T[i-1],1,maxx,e[i].v);
}
for(int i=cnt;i>=1;i--)
if(e[i].pos!=e[i+1].pos)
to[e[i].pos]=i;
for(int i=1;i<=n;i++)
if(!to[i])
to[i]=to[i-1];
long long k;
pre=1;
for(int i=1;i<=n;i++)
{
x=read();a=read();b=read();c=read();
k=(pre*a+b)%c+1;
pre=query(T[to[x]],1,maxx,k);
printf("%lld\n",pre);
}
return 0;
}
LLAP.