zoukankan      html  css  js  c++  java
  • 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
    ",(pre=query(rt[x],k,1,cnt)));
        }
        return 0;
    }    
  • 相关阅读:
    修改UISearchBar的Cancel按钮为中文等本地化问题
    Xcode6 运行程序后,右侧Debug区域的Memory显示空白解决方法
    vuec常用插件
    clipboard 实现复制
    vue 表单操作
    vue 常用功能和命令
    关闭警告&关闭eslint
    vue 添加 fastclick的支持
    url编码函数encodeURI和encodeURIComponent
    jsencrypt加解密 &&cryptico
  • 原文地址:https://www.cnblogs.com/five20/p/9651148.html
Copyright © 2011-2022 走看看