Evanyou Blog 彩带

P3168 [CQOI2015]任务查询系统

题目描述

最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的任务用三元组(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行,每行一个整数,表示查询结果。

输入输出样例

输入样例#1: 
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
输出样例#1: 
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的一个排列

 

Solution:

  本题主席树板子

  题意是个区间修改单点查询,只不过查询的时候是要前k小的和。

  每个区间$[l,r]+k$,而查询只要一个位置$x_i$的情况,想到差分序列,然后搞前缀和做到单点修改单点查询。

  我们对等级$P_i$离散,并构建主席树,由于要求前$k$小的等级和,所以多维护一个等级和的前缀和$sum$。

  对于每个询问,沿着查询的时刻的权值线段树自顶向下判断,类比求第$k$小数,每次累加返回$sum$就好了。(注意,这样查询会出现一个问题,当一个等级在同一时刻多次出现时,就会出现遍历到该等级子节点时$siz>k$,此时不能直接返回$sum$,而应返回$sum/siz*k$)

代码:

/*Code by 520 -- 9.13*/
#include<bits/stdc++.h>
#define il inline
#define ll long long
#define RE register
#define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++)
#define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--)
using namespace std;
const int N=200005;
int n,m,rt[N],*Q[N],w[N],tot,cnt,num;
struct arr{
    int pos,val,tag;
    bool operator<(const arr &a)const{return pos<a.pos;}
}a[N<<1];
struct node{
    int ls,rs,siz;
    ll sum;
}t[N*40];

int gi(){
    int a=0;char x=getchar();
    while(x<'0'||x>'9')x=getchar();
    while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+(x^48),x=getchar();
    return a;
}

il bool cmp(const int *a,const int *b){return *a<*b;}

void build(int l,int r,int &rt){
    t[rt=++tot].siz=0,t[rt].sum=0;
    if(l==r) return;
    int m=l+r>>1;
    build(l,m,t[rt].ls),build(m+1,r,t[rt].rs);
}

void update(int k,int tag,int l,int r,int lst,int &rt){
    rt=++tot;
    t[rt]=t[lst],t[rt].siz+=tag,t[rt].sum+=tag*w[k];
    if(l==r) return;
    int m=l+r>>1;
    if(k<=m) update(k,tag,l,m,t[lst].ls,t[rt].ls);
    else update(k,tag,m+1,r,t[lst].rs,t[rt].rs);
}

ll query(int rt,int k,int l,int r){
    if(k>=t[rt].siz) return t[rt].sum;
    if(l==r) return t[rt].sum/t[rt].siz*k;
    int siz=t[t[rt].ls].siz,m=l+r>>1;
    if(k<=siz) return query(t[rt].ls,k,l,m);
    else return t[t[rt].ls].sum+query(t[rt].rs,k-siz,m+1,r);
}

int main(){
    n=gi(),m=gi();
    int x,y,z;
    For(i,1,n) {
        x=gi(),y=gi(),z=gi();
        a[i]=arr{x,z,1},a[i+n]=arr{y+1,z,-1};
        Q[i]=&a[i].val,Q[i+n]=&a[i+n].val;
    }
    sort(Q+1,Q+n*2+1,cmp);
    int lst=-1;
    For(i,1,n<<1) 
        if(*Q[i]!=lst) lst=*Q[i],*Q[i]=++cnt,w[cnt]=lst;
        else *Q[i]=cnt;
    sort(a+1,a+n*2+1);
    build(1,cnt,rt[0]);
    lst=rt[0];
    for(RE int i=1,j=1;i<=m;i++) {
        rt[i]=lst;
        for(;a[j].pos==i&&j<=(n<<1);j++) 
            update(a[j].val,a[j].tag,1,cnt,lst,rt[i]),lst=rt[i];
    }
    ll pre=1,k,a,b,c;
    while(m--){
        x=gi(),a=gi(),b=gi(),c=gi();
        k=(a*pre%c+b)%c+1;
        printf("%lld\n",(pre=query(rt[x],k,1,cnt)));
    }
    return 0;
}    

 

posted @ 2018-09-15 15:52  five20  阅读(251)  评论(0编辑  收藏  举报
Live2D