BZOJ3932 || 洛谷P3168 [CQOI2015]任务查询系统【主席树】

Time Limit: 20 Sec
Memory Limit: 512 MB

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行,每行一个整数,表示查询结果。

HINT

对于100%的数据,1≤m,n,Si,Ei,Ci≤100000,0≤Ai,Bi≤100000,1≤Pi≤10000000,Xi为1到n的一个排列


题目分析

优先级pi先离散化
主席树维护时间轴,每棵权值线段树对应的是优先级的出现情况
size记录区间出现不同任务的数量,sum记录区间优先级之和
因为每个任务是一段区间,所以先差分再建主席树

#include<iostream>
#include<cstdio>
#include<cmath>
#include<queue>
#include<algorithm>
#include<cstring>
using namespace std;
typedef long long lt;
#define lowbit(x) ((x)&(-x))

int read()
{
    int f=1,x=0;
    char ss=getchar();
    while(ss<'0'||ss>'9'){if(ss=='-')f=-1;ss=getchar();}
    while(ss>='0'&&ss<='9'){x=x*10+ss-'0';ss=getchar();}
    return f*x;
}

const int maxN=2e5+10;
const int maxM=2e7+10;
int n,m;
int rt[maxM],ch[maxM][2],sz;
int size[maxM],RT[maxN];
lt sum[maxM];
int Si[maxN],Ei[maxN],pi[maxN];
int b[maxN],pos[maxN],cnt,tot;
struct node{int pos,val,k;}rem[maxN<<1];
lt ans=1;

bool cmp(node a,node b){ return a.pos<b.pos;} 

int update(int pre,int ll,int rr,int x,int k)
{
    int tt=++sz; size[tt]=size[pre]+k;  sum[tt]=sum[pre]+1ll*pos[x]*k;
    ch[tt][0]=ch[pre][0]; ch[tt][1]=ch[pre][1];
    int mid=ll+rr>>1;
    if(ll<rr)
    {
        if(x<=mid) ch[tt][0]=update(ch[pre][0],ll,mid,x,k);
        else ch[tt][1]=update(ch[pre][1],mid+1,rr,x,k);
    }
    return tt;
}

lt query(int u,int ll,int rr,int k)
{
    if(ll==rr) return 1ll*k*pos[ll];
    int mid=ll+rr>>1;
    if(k<=size[ch[u][0]]) return query(ch[u][0],ll,mid,k);
    else return sum[ch[u][0]]+query(ch[u][1],mid+1,rr,k-size[ch[u][0]]);
}

int main()
{
    m=read();n=read();
    for(int i=1;i<=m;++i)
    {
        Si[i]=read(); Ei[i]=read();
        pi[i]=b[i]=read();
    }
    
    sort(b+1,b+1+m);
    for(int i=1;i<=m;++i)
    if(i==1||b[i]!=b[i-1])
    pos[++cnt]=b[i];
    
    for(int i=1;i<=m;++i)
    {
        pi[i]=lower_bound(pos+1,pos+1+cnt,pi[i])-pos;
        rem[++tot]=(node){Si[i],pi[i],1};
        rem[++tot]=(node){Ei[i]+1,pi[i],-1};
    }
    
    sort(rem+1,rem+1+2*m,cmp); 
    int tt=1,rtn=0;
    for(int i=1;i<=n+1;++i)//差分后时间轴+1
    {
        while(tt<=tot&&rem[tt].pos==i) 
        rt[rtn+1]=update(rt[rtn],1,cnt,rem[tt].val,rem[tt].k),tt++,rtn++;
        RT[i]=rt[rtn];
    }
    
    for(int i=1;i<=n;++i)
    {
        lt Xi=read(),Ai=read(),Bi=read(),Ci=read();
        lt Ki=1+(Ai*ans+Bi)%Ci;
        if(size[RT[Xi]]<=Ki) ans=sum[RT[Xi]];//-sum[RT[Xi-1]];
        else ans=query(RT[Xi],1,cnt,Ki);
        printf("%lld\n",ans);
    }
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值