[BZOJ3932]任务查询系统

[BZOJ3932]任务查询系统

题面

最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的

任务用三元组(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的一个排列

思路

S-开始时间,E-结束时间,P-优先级,X-查询时间点,K-查询的排名

其实就是在一个轴上,寻找覆盖了点\(X\)的权值最小的\(K\)个的权值之和。

那我们考虑搞一个可持久化线段树,然后把所有工作按照优先级排序。按照优先级插入线段树,将\(S_i-E_i\)全部在tag1上+1,在tag2上+\(P_i\)

然后开始二分,每次判断\(mid\)这个版本\(tag1[X_i]\)的值有没有超过\(K_i\)然后就找到了答案。

特别的,应为\(K_i\)可能会大于\(max(tag1[X_i])\),所以每次查询之前我们先看一下最后一个版本的\(tag1[X_i]\)是不是大于\(K_i\),如果是,直接输出最后一个版本的\(tag2[X_i]\)即可。

代码

#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
#define maxn (int)(1e5+1000)
#define ll long long
ll pre,tag2[maxn<<6],sum2[maxn<<6],a,b,c,d;
int rt[maxn],tag1[maxn<<6],ls[maxn<<6],rs[maxn<<6],sum1[maxn<<6];
struct gg{
    int s,e;ll p;
}data[maxn];
ll idx;
int n,m;
bool cop(gg x,gg y){
    return x.p<y.p;
}
int build(int l,int r){
    int now=++idx;
    if(l==r)return now;
    int mid=(l+r)>>1;
    ls[now]=build(l,mid);
    rs[now]=build(mid+1,r);
    return now;
}
int update(int x,int l,int r,int tl,int tr,int val1,ll val2){
    int now=++idx;
    ls[now]=ls[x],rs[now]=rs[x],sum1[now]=sum1[x],sum2[now]=sum2[x],tag1[now]=tag1[x],tag2[now]=tag2[x];
    sum1[now]=sum1[x]+(min(r,tr)-max(l,tl)+1)*val1;sum2[now]=sum2[x]+(min(r,tr)-max(l,tl)+1)*val2;
    int mid=(l+r)>>1;
    if(tl<=l&&r<=tr){
        tag1[now]+=val1;tag2[now]+=val2;return now;
    }
    if(tl<=mid){
        ls[now]=update(ls[x],l,mid,tl,tr,val1,val2);
    }
    if(tr>=mid+1){
        rs[now]=update(rs[x],mid+1,r,tl,tr,val1,val2);
    }
    return now;
}
ll query(int x,int l,int r,int tl,int tr,int add1,ll add2,int mod){
    if(tl<=l&&r<=tr){
        if(mod==1)return add1+sum1[x];
        else return add2+sum2[x];
    }
    add1+=tag1[x];add2+=tag2[x];
    ll ans=0;int mid=(l+r)>>1;
    if(tl<=mid){
        ans+=query(ls[x],l,mid,tl,tr,add1,add2,mod);
    }
    if(tr>=mid+1){
        ans+=query(rs[x],mid+1,r,tl,tr,add1,add2,mod);
    }
    return ans;
}
int main(){
//  /freopen("in","r",stdin);
    pre=1;
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;i++){
        scanf("%d%d%lld",&data[i].s,&data[i].e,&data[i].p);
    }
    sort(data+1,data+1+m,cop);
    rt[0]=build(1,n);
    for(int i=1;i<=m;i++){
        rt[i]=update(rt[i-1],1,n,data[i].s,data[i].e,1,data[i].p);
    }
    for(int i=1;i<=n;i++){
        scanf("%lld%lld%lld%lld",&d,&a,&b,&c);
        ll k=1+(a*pre+b)%c;int l=1,r=m;
        while(l<r){
            int mid=(l+r+1)>>1;
            if(query(rt[mid],1,n,d,d,0,0,1)<=k){
                l=mid;
            }else{
                r=mid-1;
            }
        }
        pre=query(rt[l],1,n,d,d,0,0,2);
        printf("%lld\n",pre);
    }
    return 0;
}

转载于:https://www.cnblogs.com/GavinZheng/p/10854717.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值