【BZOJ3932】任务查询系统

                                 3932: [CQOI2015]任务查询系统

                                                               Time Limit: 20 Sec  Memory Limit: 512 MB
                                                                             Submit: 4713  Solved: 1588

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 依次修改肯定是不行的,所以我们可以用类似差分的思想,在 L 处加上这个数,在 R+1 处减去这个数,然后从1~m 扫一遍建树就可以了,询问就是很常规的问题了。

 

代码:

#include <bits/stdc++.h>
#define LL long long
using namespace std;
  
const int Max=100100;
int n,m,q,sz,mn=1e8,mx=-1e8,mark;
int root[Max*50],flag[Max*50];
LL p=1;
struct shu{int l,r,size;LL sum;};
shu tree[Max*50];
vector<int>s[Max],t[Max];
  
inline LL get_int()
{
    LL x=0,f=1;
    char c;
    for(c=getchar();(!isdigit(c))&&(c!='-');c=getchar());
    if(c=='-') {f=-1;c=getchar();}
    for(;isdigit(c);c=getchar()) x=(x<<3)+(x<<1)+c-'0';
    return x*f;
}
  
inline void NEW(int &rt,int fa){tree[rt=++sz]=tree[fa];flag[rt]=mark;}
 
inline void build(int &root,int fa,int l,int r,int num,int f)
{
    if(flag[fa]!=mark) NEW(root,fa);
    tree[root].sum+=(LL)f*num,tree[root].size+=f;
    if(l==r) return;
    int mid = l + r >> 1;
    if(num <= mid) build(tree[root].l,tree[fa].l,l,mid,num,f);
    else build(tree[root].r,tree[fa].r,mid+1,r,num,f);
}
  
inline LL Q(int root,int l,int r,int k)
{
    if(l==r) return (LL)l*k;    //注意不能返回sum[root]!!
    int mid = l + r >> 1;
    if(k <= tree[tree[root].l].size) return Q(tree[root].l,l,mid,k);
    else return (LL)Q(tree[root].r,mid+1,r,k-tree[tree[root].l].size) + tree[tree[root].l].sum;
}
  
int main()
{
    n=get_int(),m=get_int();
    for(int i=1;i<=n;i++)
    {
       int x=get_int(),y=get_int(),z=get_int();
       mn=min(mn,x),mx=max(mx,y+1);
       s[x].push_back(z),t[y].push_back(z);
    }
    for(int i=mn;i<=mx+1;i++)
    {
      NEW(root[i],root[i-1]),mark++;
      for(int j=0;j<s[i].size();j++) build(root[i],root[i],1,1e7,s[i][j],1);
      for(int j=0;j<t[i-1].size();j++) build(root[i],root[i],1,1e7,t[i-1][j],-1);
    }
  
    for(int i=1;i<=m;i++)
    {
      LL x=get_int(),a=get_int(),b=get_int(),c=get_int(),k=1+(a*p+b)%c;
      if(tree[root[x]].size <= k) cout<<(p=tree[root[x]].sum)<<"\n";
      else cout<<(p=Q(root[x],1,1e7,k))<<"\n";
    }
  
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值