bzoj 3932 [CQOI2015]任务查询系统 主席树

题目:

http://www.lydsy.com/JudgeOnline/problem.php?id=3932

题意:

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行,每行一个整数,表示查询结果。

思路:

首先把优先级离散化,然后用差分数组的思想,更新到主席树上去,主席树维护两个值,管辖区间的区间和与管辖区间内元素个数。

#include 

using namespace std;

typedef long long ll;
const int N = 100000 + 10, INF = 0x3f3f3f3f;

struct node
{
    int x, tp, p, v;
}a[N*2];

int lson[N*50], rson[N*50], siz[N*50];
ll sum[N*50];
int root[N];
int b[N], c[N], d[N];
int tot;
bool _cmp_(int x, int y)
{
    return d[x] < d[y];
}
bool cmp(node a, node b)
{
    return a.x < b.x;
}
void update(int &x, int last, int l, int r, int val, int v1, int v2)
{
    x = ++tot;
    lson[x] = lson[last], rson[x] = rson[last], sum[x] = sum[last]+v1, siz[x] = siz[last]+v2;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(val <= mid) update(lson[x], lson[last], l, mid, val, v1, v2);
    else update(rson[x], rson[last], mid+1, r, val, v1, v2);
}
ll query(int x, int l, int r, int k)
{
    if(l == r) return sum[x];
    int mid = (l + r) >> 1;
    if(k <= siz[lson[x]]) return query(lson[x], l, mid, k);
    else return sum[lson[x]] + query(rson[x], mid+1, r, k - siz[lson[x]]);
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    int x, y, z, num = 0;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d%d", &x, &y, &z);
        b[i] = i, d[i] = z;
        a[++num].x = x, a[num].p = z, a[num].v = 1;
        a[++num].x = y+1, a[num].p = -z, a[num].v = -1;
    }
    //这份代码对离散化有要求,要求离散化后相同的值不一样,即离散化结果为1~n,否则会出错
    sort(b + 1, b + 1 + n, _cmp_);
    for(int i = 1; i <= n; i++) c[b[i]] = i;
    num = 0;
    for(int i = 1; i <= n; i++) a[++num].tp = c[i], a[++num].tp = c[i];
    sort(a + 1, a + 1 + num, cmp);
    int j = 1;
    for(int i = 1; i <= m; i++)
    {
        root[i] = root[i-1];
        while(a[j].x == i) update(root[i], root[i], 1, n, a[j].tp, a[j].p, a[j].v), j++;
    }
    ll ans = 1;
    for(int i = 1; i <= m; i++)
    {
        int x, a, b, c;
        scanf("%d%d%d%d", &x, &a, &b, &c);
        int k = 1 + (a * ans + b) % c;
        ans = query(root[x], 1, n, k);
        printf("%lld\n", ans);
    }
    return 0;
}

另外一种写法,首先也是离散化优先级,主席树只维护所管辖区间的元素个数,查询的时候,一直查询到叶节点

#include 

using namespace std;

typedef long long ll;
const int N = 100000 + 10, INF = 0x3f3f3f3f;

struct node
{
    int x, tp, p, v;
}a[N*2];

int lson[N*50], rson[N*50], siz[N*50];
int root[N];
int b[N], c[N], d[N];
int tot;
bool cmp(node a, node b)
{
    return a.x < b.x;
}
void update(int &x, int last, int l, int r, int val, int v)
{
    x = ++tot;
    lson[x] = lson[last], rson[x] = rson[last], siz[x] = siz[last]+v;
    if(l == r) return;
    int mid = (l + r) >> 1;
    if(val <= mid) update(lson[x], lson[last], l, mid, val, v);
    else update(rson[x], rson[last], mid+1, r, val, v);
}
ll query(int x, int l, int r, int k)
{
    if(k > siz[x]) k = siz[x];
    if(l == r) return 1LL * k * b[l];
    int mid = (l + r) >> 1;
    if(k <= siz[lson[x]]) return query(lson[x], l, mid, k);
    else return query(lson[x], l, mid, siz[lson[x]]) + query(rson[x], mid+1, r, k - siz[lson[x]]);
}
int main()
{
    int n, m;
    scanf("%d%d", &n, &m);
    int x, y, z, num = 0;
    for(int i = 1; i <= n; i++)
    {
        scanf("%d%d%d", &x, &y, &z);
        b[i] = z;
        a[++num].x = x, a[num].p = z, a[num].v = 1;
        a[++num].x = y+1, a[num].p = -z, a[num].v = -1;
    }
    sort(b + 1, b + 1 + n);
    int len = unique(b + 1, b + 1 + n) - b - 1;
    for(int i = 1; i <= num; i += 2)
    {
        a[i].tp = lower_bound(b + 1, b + 1 + len, a[i].p) - b;
        a[i+1].tp = a[i].tp;
    }
    sort(a + 1, a + 1 + num, cmp);
    int j = 1;
    for(int i = 1; i <= m; i++)
    {
        root[i] = root[i-1];
        while(a[j].x == i) update(root[i], root[i], 1, len, a[j].tp, a[j].v), j++;
    }
    ll ans = 1;
    for(int i = 1; i <= m; i++)
    {
        int x, a, b, c;
        scanf("%d%d%d%d", &x, &a, &b, &c);
        int k = 1 + (a * ans + b) % c;
        ans = query(root[x], 1, len, k);
        printf("%lld\n", ans);
    }
    return 0;
}

你可能感兴趣的:(主席树)