• bzoj3932 [CQOI2015]任务查询系统


    3932: [CQOI2015]任务查询系统

    Time Limit: 20 Sec  Memory Limit: 512 MB
    Submit: 4113  Solved: 1334
    [Submit][Status][Discuss]

    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的一个排列
    分析:主席树的第一题......发现自己理解地不是很深.
              若对于每一个时间建主席树的话,第i棵可以用来维护时间为1~i的优先级在[x,y]的任务个数和优先级之和.对于每一个时间点都建主席树则会有点浪费,因为每次更改操作只会设计到2个时间点.考虑用操作来建主席树.第i棵可以维护第1~i次操作后优先级在[x,y]的任务个数和优先级之和.那么每一次操作只需要在初始时间和结束时间+1处更改就行了(类似于差分).对操作的时间排序,接着求出每个时间点最后被影响的操作序号.最后查询就好了.
              搞清楚主席树表示的意义很重要!碰到第k小/大这种字眼也要很快反应过来该用什么方法,还要知道利用主席树要维护什么东西!与权值线段树联系起来思考.
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <algorithm>
    
    using namespace std;
    
    const int maxn = 200010;
    
    typedef long long ll;
    
    ll ans;
    int n,m,tot,cur[maxn],cnt,root[maxn],mx;
    
    struct node
    {
        int left,right,sizee;
        ll sum;
    }e[maxn * 25];
    
    struct node2
    {
        int pos,val;
    }a[maxn];
    
    bool cmp(node2 a,node2 b)
    {
        return a.pos < b.pos;
    }
    
    void update(int l,int r,int x,int &y,int v)
    {
        e[y = ++cnt] = e[x];
        e[y].sizee += (v > 0 ? 1 : -1);
        e[y].sum += v;
        if (l == r)
            return;
        int mid = (l + r) >> 1;
        if (abs(v) <= mid)
            update(l,mid,e[x].left,e[y].left,v);
        else
            update(mid + 1,r,e[x].right,e[y].right,v);
    }
    
    ll query(int l,int r,int x,int k)
    {
        if (e[x].sizee <= k)
            return e[x].sum;
        if (l == r)
            return 1LL * l * k;
        int mid = (l + r) >> 1;
        if (k <= e[e[x].left].sizee)
            return query(l,mid,e[x].left,k);
        else
            return e[e[x].left].sum + query(mid + 1,r,e[x].right,k - e[e[x].left].sizee);
    }
    
    int main()
    {
        scanf("%d%d",&n,&m);
        for(int i = 1; i <= n; i++)
        {
            int x,y,z;
            scanf("%d%d%d",&x,&y,&z);
            a[++tot].pos = x;
            a[tot].val = z;
            a[++tot].pos = y + 1;
            a[tot].val = -z;
            mx = max(mx,z);
        }
        sort(a + 1,a + 1 + tot,cmp);
        for (int i = 1; i <= tot; i++)
            update(1,mx,root[i - 1],root[i],a[i].val);
        for (int i = tot; i >= 1; i--) //维护每一个被更改的时间点最后在哪里被更改的
            if (a[i].pos != a[i + 1].pos)
                cur[a[i].pos] = root[i];
        for (int i = 1; i <= m; i++) //如果当前时间点没有被更改,那么就和前一个时间点的情况一样
            if (!cur[i])
                cur[i] = cur[i - 1];
        ans = 1;
        for (int i = 1; i <= m; i++)
        {
            ll t,x,y,z,k;
            scanf("%lld%lld%lld%lld",&t,&x,&y,&z);
            k = (1LL * x * ans + y) % z + 1;
            ans = query(1,mx,cur[t],k);
            printf("%lld
    ",ans);
        }
    
        return 0;
    }
  • 相关阅读:
    MATLAB 模板匹配
    ACDSee15 教你如何轻松在图片上画圈圈、画箭头、写注释
    Qt 显示一个窗体,show()函数和exec()函数有什么区别?
    Qt 将窗体变为顶层窗体(activateWindow(); 和 raise() )
    Qt QSS样式化 菜单Qmenu&QAction
    Qt 获取文件夹中的文件夹名字
    Qt 删除文件夹或者文件
    欧洲终于承认“工业4.0”失败,互联网经济严重落后中美
    深入浅出数据结构
    浅谈城市大脑与智慧城市发展趋势
  • 原文地址:https://www.cnblogs.com/zbtrs/p/8279942.html
Copyright © 2020-2023  润新知