P3168 [CQOI2015]任务查询系统 主席树 差分数组

  现在有一群任务,每个任务都有开始和结束的时间和一个优先级,给你所有任务的开始结束时间和优先级,问你在某个时间点优先级最小的k个的优先级的和是多少.

普通的主席树是单点修改 区间查询   这题正好相反

可以用差分数组来做  区间查询改为1-i的前缀和

注意copy结点的方式 不能简单的复制T  还有son  t num

重复累加的操作  要写成T[i] T[i]      而不是  T[i-1] T[i]

主席树的范围只和放入的数据的离散化下标有关   和历史版本号没有任何关系

这题的时间为历史版本号  和主席树的范围没有关系

#include<bits/stdc++.h>
using namespace std;
//input by bxd
#define rep(i,a,b) for(int i=(a);i<=(b);i++)
#define repp(i,a,b) for(int i=(a);i>=(b);--i)
#define ll long long
#define see(x) (cerr<<(#x)<<‘=‘<<(x)<<endl)
#define pb push_back
#define inf 0x3f3f3f3f
#define CLR(A,v)  memset(A,v,sizeof A)
typedef pair<int,int>pii;
//////////////////////////////////
const int N=2e6+10;
int son[N<<5][2];
ll t[N<<5],num[N<<5];
int T[N<<5],ncnt;

struct node {int x,v;ll flag; } a[N];
int n,m;
ll b[N];
void build(int l,int r,int &pos)
{
    pos=++ncnt;
    if(l==r)return ;
    int m=l+r>>1;
    build(l,m,son[pos][0]);
    build(m+1,r,son[pos][1]);
}
void up(int x,int flag,int l,int r,int pre,int &pos)
{
    pos=++ncnt;
    son[pos][0]=son[pre][0];
    son[pos][1]=son[pre][1];
    t[pos]=t[pre]+flag*b[x];
    num[pos]=num[pre]+flag;

    if(l==r){return ;}
    int m=l+r>>1;
    if(x<=m)up(x,flag,l,m,son[pos][0],son[pos][0]);
    else up(x,flag,m+1,r,son[pos][1],son[pos][1]);
}

int qsum(int k,int l,int r,int pos)
{
    if(l==r)return min(k*t[pos]/num[pos],t[pos]);
    if(num[pos]<=k)return t[pos];
    int m=l+r>>1;
    if(num[son[pos][0]]>=k)return qsum(k,l,m,son[pos][0]);
    else return t[son[pos][0]]+qsum(k-num[son[pos][0]],m+1,r,son[pos][1]);
}
void cpy(int &pos,int pre)
{
    pos=++ncnt;
    son[pos][0]=son[pre][0];
    son[pos][1]=son[pre][1];
    t[pos]=t[pre];
    num[pos]=num[pre];
}
int main()
{
    scanf("%d%d",&n,&m);
    rep(i,1,n)
    {
        int x,y;ll z;scanf("%d%d%lld",&x,&y,&z);
        a[2*i-1]=(node){x,z,1};
        a[2*i  ]=(node){y+1,z,-1};
        b[i]=z;
    }
    sort(b+1,b+1+n);
    int nn=unique(b+1,b+1+n)-b-1;
    sort(a+1,a+1+2*n,[](node a,node b){return a.x<b.x;}  );
    build(1,nn,T[0]);

    int pos=1;
    rep(i,1,m)
    {
        cpy(T[i],T[i-1]);
        while(pos<=2*n&&a[pos].x==i)
        {
            up(lower_bound(b+1,b+1+nn,a[pos].v)-b,a[pos].flag,1,nn,T[i],T[i]); pos++;//注意这里如果写成T[i-1],T[i]  就不能满足重复更新
        }
    }
    ll ans=1,A,B,C,x,k;
    rep(j,1,m)
    {
        scanf("%lld%lld%lld%lld",&x,&A,&B,&C);
        k=1+(A*ans+B)%C;
        if(k>=num[T[x]]) ans=t[T[x]];
        else
        ans=qsum((int)k,1,nn,T[x]);
        printf("%lld\n",ans);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/bxd123/p/11281463.html

时间: 2024-11-29 04:21:47

P3168 [CQOI2015]任务查询系统 主席树 差分数组的相关文章

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

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

BZOJ 3932: [CQOI2015]任务查询系统 | 主席树练习题

题目: 洛谷也能评测 题解: De了好长时间BUG发现是自己sort前面有一行for没删,气死. 题目询问第x秒时候前k小的P值之和. 朴素想法: 我们可以把P值离散化,然后对于每个时刻建一棵定义域是离散化后P值的线段树 每个节点维护了这个节点代表区间的任务个数和这些任务离散化之前的P值之和, 对于每个在这个时间段的任务,插入,即在p位置单点修改 询问就是类似二叉查找树的写法 高级想法: 首先把一段任务拆成两个:添加和删除,用三元组(t,p,d)表示,d=1表示插入,d=-1表示删除 对于第ma

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

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

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

版权声明:本文为博主原创文章,未经博主允许不得转载. bzoj 3832 题意: 有一堆任务,每个任务都有一个起始时间和终止时间,外加一个优先级 . 查询第xi秒优先级最小的k任务的优先级的和,如果第xi秒任务数小于k,则输出所有任务的优先级的和 . 解法: 每一秒都建立一颗线段树,线段树记录该时间点每个优先级出现的次数 . 可以把每个任务拆成两部分,一个在某个时间点该优先级次数加1,另一个就是减1了,然后按时间排序,随意搞搞就行了 . code 1 #include <iostream> 2

luogu P3168 [CQOI2015] 任务查询系统

传送门 区间修改单点查询的主席树 改个差分就行了 首先强制在线的是查询 所以修改可以一次全读进来然后离散并且插进去 没有影响 这里的话先全修改完再查询 可以放弃树状数组直接维护差分 然后主席树维护区间数字个数和整体和 最后分到叶子节点的时候注意去对应个数个数字加进去就行 然后有个操作就是一次把所有这个点上的差分数组都加进去 不开long long *** Code: 1 #include<cstdio> 2 #include<iostream> 3 #include<cstr

P3168 [CQOI2015]任务查询系统

介绍本题的两种做法: 方法1 前置芝士 线段树:一个很重要的数据结构. 树状数组:一个很重要的数据结构. 具体实现 区间修改,单点查询很容易就会想到树状数组了,至于查询前k个数的和又可以丢给权值线段树去干,所以第一种很显然的方法就是树状数组套一个线段树实现. 代码 #include<bits/stdc++.h> #define REP(i,first,last) for(int i=first;i<=last;++i) #define DOW(i,first,last) for(int

●洛谷P3168 [CQOI2015]任务查询系统

题链: https://www.luogu.org/problemnew/show/P3168题解: 主席树 强制在线? 那就直接对每一个前缀时间建一个线段树(可持久化线段树),线段树维护优先度权值. 代码: #include<bits/stdc++.h> #define MAXN 100005 using namespace std; int tmp[MAXN]; int N,M,tnt; long long pre=1; struct Event{ int ent; int p[MAXN*

洛谷P3168 [CQOI2015]任务查询系统

#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #include<vector> #define MAXN 100000+10 #define Nd Node* #define pii pair<int,int> #define mp make_pair #define ft first #define sc second #define

3932: [CQOI2015]任务查询系统

3932: [CQOI2015]任务查询系统 Time Limit: 20 Sec  Memory Limit: 512 MBSubmit: 2559  Solved: 819[Submit][Status][Discuss] Description 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的 任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行 ),其优先级为P