zoukankan      html  css  js  c++  java
  • 【bzoj3932】[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行,每行一个整数,表示查询结果。

    样例输入

    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

    样例输出

    2
    8
    11


    题解

    主席树(不需要修改)

    先将所有任务读进来,将优先级离散化,再按时间排序加入主席树中。

    开始时间加进来,结束时间+1减去。

    查询时,相当于查询[1,x]这一段区间,所以不用变为两树相减的形式。

    先二分查找出最后一个小于等于x的(即第一个大于x的数-1),然后查询。

    注意:需要开long long;sum数组修改时要加减原值,不能是离散化后的值;查询时如果l和r相等,需要返回l的原值乘p

    upperbound码错调了半天。。。

    #include <cstdio>
    #include <algorithm>
    #define N 200010
    using namespace std;
    typedef long long lint;
    struct data
    {
        lint ti , p , mk;
    }a[N];
    lint v[N] , top , root[N] , lp[N << 6] , rp[N << 6] , si[N << 6] , sum[N << 6] , tot;
    lint vti[N];
    bool cmp1(data a , data b)
    {
        return a.p < b.p;
    }
    bool cmp2(data a , data b)
    {
        return a.ti < b.ti;
    }
    void pushup(lint x)
    {
        si[x] = si[lp[x]] + si[rp[x]];
        sum[x] = sum[lp[x]] + sum[rp[x]];
    }
    void update(lint x , lint &y , lint l , lint r , lint p , lint a)
    {
        y = ++tot;
        if(l == r)
        {
            si[y] = si[x] + a;
            sum[y] = sum[x] + v[p] * a;
            return;
        }
        lint mid = (l + r) >> 1;
        if(p <= mid) rp[y] = rp[x] , update(lp[x] , lp[y] , l , mid , p , a);
        else lp[y] = lp[x] , update(rp[x] , rp[y] , mid + 1 , r , p , a);
        pushup(y);
    }
    lint query(lint y , lint l , lint r , lint p)
    {
        if(l == r)
            return v[l] * p;
        lint mid = (l + r) >> 1;
        if(p <= si[lp[y]]) return query(lp[y] , l , mid , p);
        else return query(rp[y] , mid + 1 , r , p - si[lp[y]]) + sum[lp[y]];
    }
    int main()
    {
        lint n , m , i , x , y , z , pre = 1 , c , k , p;
        scanf("%lld%lld" , &n , &m);
        for(i = 1 ; i <= n ; i ++ )
        {
            scanf("%lld%lld%lld" , &x , &y , &z);
            a[2 * i - 1].ti = x;
            a[2 * i].ti = y + 1;
            a[2 * i - 1].p = a[2 * i].p = z;
            a[2 * i - 1].mk = 1;
            a[2 * i].mk = -1;
        }
        sort(a + 1 , a + 2 * n + 1 , cmp1);
        for(i = 1 ; i <= 2 * n ; i ++ )
        {
            if(a[i].p != v[top]) v[++top] = a[i].p;
            a[i].p = top;
        }
        sort(a + 1 , a + 2 * n + 1 , cmp2);
        for(i = 1 ; i <= 2 * n ; i ++ )
        {
            vti[i] = a[i].ti;
            update(root[i - 1] , root[i] , 1 , top , a[i].p , a[i].mk);
        }
        while(m -- )
        {
            scanf("%lld%lld%lld%lld" , &c , &x , &y , &z);
            k = 1 + (x * pre + y) % z;
            p = upper_bound(vti + 1 , vti + 2 * n + 1 , c) - vti - 1;
            if(si[root[p]] < k) pre = sum[root[p]];
            else pre = query(root[p] , 1 , top , k);
            printf("%lld
    " , pre);
        }
        return 0;
    }
  • 相关阅读:
    安卓手机!用swiper做轮播效果,两张图片之间会有一个像素的空白
    手机端swiper快速滑动会有白屏
    axios请求下载excel文件
    人人都能学会的webpack5搭建vue3项目(二)配置Vue
    人人都能学会的webpack5搭建vue3.0项目,可应用于生产环境 (一)
    mybatis 生成 mapper文件
    超强工具类系列
    mybatis 自动生成mapper文件
    面试
    linux安装mysql8.0.25
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/6295577.html
Copyright © 2011-2022 走看看