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行,每行一个整数,表示查询结果。
Sample Input
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
Sample Output
2
8
11
HINT
样例解释
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的一个排列
题解
区间修改单点求值我们可以差分一下
那么主席树其实也是可以的嘻嘻嘻
对于l~r这段区间,rt[l]加权 rt[r+1]减去相同的权
最后前缀和起来,单点询问
主席树里面记录两个权,c和sum,c表示这棵子树中有的节点数,sum表示这棵子树里面有的权值和
然后直接找就OK了
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long LL;
struct LSnode{int l,r;LL op;}w[210000];
bool cmp(LSnode n1,LSnode n2){return n1.op<n2.op;}
struct node
{
int lc,rc,c;LL sum;
}tr[5110000];int trlen;
int rt[210000];
void add(int &now,int l,int r,int p,int op,LL del)
{
if(now==0)now=++trlen;
tr[now].c+=op;tr[now].sum+=del;
if(l==r)return ;
int mid=(l+r)/2;
if(p<=mid)add(tr[now].lc,l,mid,p,op,del);
else add(tr[now].rc,mid+1,r,p,op,del);
}
void merge(int &x,int y)
{
if(x==0){x=y;return ;}
if(y==0)return ;
tr[x].c+=tr[y].c;tr[x].sum+=tr[y].sum;
merge(tr[x].lc,tr[y].lc);
merge(tr[x].rc,tr[y].rc);
}
int n,m;LL lastans;
LL findKth(int x,int l,int r,int K)
{
if(K>tr[x].c)return tr[x].sum;
if(l==r){return (LL)K*(tr[x].sum/tr[x].c);}
int lc=tr[x].lc,rc=tr[x].rc,mid=(l+r)/2;
if(K<=tr[lc].c)return findKth(lc,l,mid,K);
else return findKth(rc,mid+1,r,K-tr[lc].c)+tr[lc].sum;
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1;i<=n;i++)scanf("%d%d%lld",&w[i].l,&w[i].r,&w[i].op);
sort(w+1,w+1+n,cmp);
int cnt=0;
for(int i=1;i<=n;i++)
{
if(w[i].op==w[i-1].op)add(rt[w[i].l],1,n,cnt,1,w[i].op),add(rt[w[i].r+1],1,n,cnt,-1,-w[i].op);
else cnt++,add(rt[w[i].l],1,n,cnt,1,w[i].op),add(rt[w[i].r+1],1,n,cnt,-1,-w[i].op);
}
for(int i=1;i<=n;i++)merge(rt[i],rt[i-1]);
lastans=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*lastans+b)%c;
lastans=findKth(rt[x],1,n,K);
printf("%lld\n",lastans);
}
return 0;
}

本文介绍了一种针对超级计算机任务管理系统的查询算法。该系统利用主席树数据结构处理任务的优先级查询,支持快速获取指定时刻运行的任务中优先级最低的若干任务的优先级之和。
502

被折叠的 条评论
为什么被折叠?



