【BZOJ3932】【CQOI2015】任务查询系统 可持久化线段树

链接:

#include <stdio.h>
int main()
{
    puts("转载请注明出处[vmurder]谢谢");
    puts("网址:blog.csdn.net/vmurder/article/details/44937681");
}

题解:

首先肯定要用线段树。

如果没有强制在线,那么直接把询问排个序然后按秩插入、删除、查询。普通线段树就好了,但是这道题强制在线,就需要可持久化线段树了。

线段树的每个区间记录[x:这段区间有的权值总和]、[n:这段区间有多少个权值]

然后每个版本表示一个时间点的线段树。

这道题每个版本可能有多个节点被修改,所以我们可以先当成多个版本一个个修改,然后最后一个的版本root记录为当前版本root。这样的时空复杂度基本是严格的。

我们还可以修改时传一个修改区间,见我的代码,可以省一部分空间(可卡,但是无论如何理论时间空间一定更优,时间上存在少许常数)。

代码:

#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
#define N 101000
#define LOGN 35
#define ls s[now].l
#define rs s[now].r
#define inf 0x3f3f3f3f
using namespace std;
struct LSH
{
    int x,id;
    bool operator < (const LSH &A)const{return x<A.x;}
}lsh[N];
struct OPT
{
    int p,x,d;
    bool operator < (const OPT &A)const{return p==A.p?x<A.x:p<A.p;}
}seq[N<<1];
struct Segment_Tree
{
    int l,r,n;
    long long x;
}s[N*LOGN];
int cnt,root[N];
inline void pushup(int now)
{
    s[now].x=s[ls].x+s[rs].x;
    s[now].n=s[ls].n+s[rs].n;
}
void add(int last,int &now,int l,int r,int sl,int sr)
{
    now=++cnt;
    if(l==r)
    {
        int t=(sr-sl+1);
        if(seq[sl].d)
        {
            s[now].x=s[last].x+(long long)lsh[l].x*t;
            s[now].n=s[last].n+t;
        }
        else {
            s[now].x=s[last].x-(long long)lsh[l].x*t;
            s[now].n=s[last].n-t;
        }
        return ;
    }
    int mid=l+r>>1;
    if(seq[sr].x<=mid)
    {
        rs=s[last].r;
        add(s[last].l,ls,l,mid,sl,sr);
    }
    else if(seq[sl].x>mid)
    {
        ls=s[last].l;
        add(s[last].r,rs,mid+1,r,sl,sr);
    }
    else {
        int p;
        for(p=sl;seq[p].x<=mid;p++);
        add(s[last].l,ls,l,mid,sl,p-1);
        add(s[last].r,rs,mid+1,r,p,sr);
    }
    pushup(now);
}
long long query(int now,int l,int r,int k)
{
    if(k>=s[now].n)return s[now].x;
    if(l==r)return (long long)k*lsh[l].x;
    int mid=l+r>>1;
    if(s[ls].n>=k)return query(ls,l,mid,k);
    else return s[ls].x+query(rs,mid+1,r,k-s[ls].n);
}
int n,m,u;
long long pre=1;
int getk(int a,int b,int c){return 1+(pre*a+b)%c;}
int main()
{
    int i,j,k;
    int a,b,c;

    scanf("%d%d",&n,&m);
    for(i=1;i<=n;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        lsh[i].x=c,lsh[i].id=i;
        seq[i].p=a,seq[i].d=1,seq[i+n].p=b+1;
    }
    sort(lsh+1,lsh+n+1);
    for(i=1;i<=n;i++)
    {
        if(lsh[i].x!=lsh[i-1].x)lsh[++u].x=lsh[i].x;
        seq[lsh[i].id].x=seq[lsh[i].id+n].x=u;
    }
    n<<=1;
    sort(seq+1,seq+n+1);
    for(k=0,i=1;i<=n;i=j)
    {
        for(k++;k<seq[i].p&&k<=m;k++)root[k]=root[k-1];
            if(k>m)break;
        for(j=i+1;seq[j].p==seq[i].p;j++);
        add(root[k-1],root[k],1,u,i,j-1);
    }
    while(m--)
    {
        scanf("%d%d%d%d",&k,&a,&b,&c);
        pre=query(root[k],1,u,getk(a,b,c));
        printf("%lld\n",pre);
    }
    return 0;
}
时间: 2024-11-10 14:33:48

【BZOJ3932】【CQOI2015】任务查询系统 可持久化线段树的相关文章

BZOJ 3932 CQOI2015 任务查询系统 可持久化线段树

题目大意见http://pan.baidu.com/s/1o6zajc2 主席树裸上就好了... #include <cstdio> #include <cstring> #include <iostream> #include <algorithm> #define M 100100 using namespace std; struct Segtree{ Segtree *ls,*rs; int size; long long sum; void* op

BZOJ 3932 CQOI 2015 任务查询系统 可持久化线段树

题目大意 给出一些任务开始的时间,结束的时间,和优先级.问在第k秒时的第k大优先级,和前k小优先级的和. 思路 CQOI太良心,所有题都是512M. 这个题只需要按照时间轴弄一个可持久化线段树就行了,每个时间点对应着一个权值线段树,维护子节点的和和个数. 注意在没有操作的时候,当前时间点的线段树要复制上一个时间点的线段树. CODE #define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstring> #inclu

[bzoj3932][CQOI2015]任务查询系统-题解[主席树][权值线段树]

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

bzoj3932 [CQOI2015]任务查询系统——主席树

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3932 第二道主席树!本来想自己手胡一下,但是还是写不下去了... 参考博客:https://www.cnblogs.com/CQzhangyu/p/6295579.html 就是对每个时间节点建一棵权值线段树,节点太多所以开成主席树: WA了好久,竟然是错在二分的地方了???看了半天还是不知道为什么错,那个写法已经用了好久了啊... 代码如下: #include<iostream> #i

BZOJ3932: [CQOI2015]任务查询系统

传送门 真不知道我没学主席树之前是有什么勇气说自己高级数据结构以及学的七七八八了. 这道题应该也是算是主席树的经典运用. 刚开始脑抽了,想把(S,E,P)的处理直接在线用树状数组xjb搞搞算了.写完后才意识到树状数组无法(很难?)实现区间修改. 然后想了想既然这个是一下子把所有修改都放上了直接用树状数组差分一下不就好了! 然后又深感自己制杖,为什么要用树状数组差分呢,直接开几个vector维护一下就行了. 说是修改,本质上是不带修改的主席树,很快搞完.WA,眼查,无果,跟踪,无果. 拍了几组小数

[bzoj3932][CQOI2015][任务查询系统] (主席树)

Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为Pi.同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同.调度系统会经常向 查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个 )的优先级之和是多少.特别的,如

[您有新的未分配科技点]可,可,可持久化!?------可持久化线段树普及版讲解

最近跑来打数据结构,于是我决定搞一发可持久化,然后发现--一发不可收啊-- 对于可持久化数据结构,其最大的特征是"历史版本查询",即可以回到某一次修改之前的状态,并继续操作:而这种"历史版本查询"会衍生出其他一些强大的操作. 今天,我们主要讲解可持久化线段树.其实,它的另外一个名字"主席树"似乎更加为人所知(主席%%%). 主席树与普通的线段树相比,多出来的操作是在修改时复制修改的一条链,这个操作的过程大概长下面这样. 至于为什么要这样做-- 对

【BZOJ-4408】神秘数 可持久化线段树

4408: [Fjoi 2016]神秘数 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 475  Solved: 287[Submit][Status][Discuss] Description 一个可重复数字集合S的神秘数定义为最小的不能被S的子集的和表示的正整数.例如S={1,1,1,4,13}, 1 = 1 2 = 1+1 3 = 1+1+1 4 = 4 5 = 4+1 6 = 4+1+1 7 = 4+1+1+1 8无法表示为集合S的子集的

【BZOJ 3674】可持久化并查集加强版&amp;【BZOJ 3673】可持久化并查集 by zky 用可持久化线段树破之

最后还是去掉异或顺手A了3673,,, 并查集其实就是fa数组,我们只需要维护这个fa数组,用可持久化线段树就行啦 1:判断是否属于同一集合,我加了路径压缩. 2:直接把跟的值指向root[k]的值破之. 3:输出判断即可. 难者不会,会者不难,1h前我还在膜这道题,现在吗hhh就当支持下zky学长出的题了. 3673: #include<cstdio> #include<cstring> #include<algorithm> #define read(x) x=ge