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\n",ans);
    }

    return 0;
}

 

posted @ 2018-01-13 17:10  zbtrs  阅读(214)  评论(0编辑  收藏  举报