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

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到j的话就给第i个版本++,第j+1个版本--;

但是我们需要考虑几个事情

1.pi太大,需要离散化,这是很显然的。

2.修改了第x个版本的话后面所有版本都需要更改。

对于1我的方法是把所有优先级先序排序去重然后依次放到数组里,因为排了序了所以它们的大小关系不会改变,然后通过二分找到离散化以后的值(但是被dalao嘲讽了)

对于2我的方法是把所有操作按时间点大小先序排序,然后依次进行操作,如果当前的操作点比目前建的树要大那就开到那个时间点

这个意思

1 for(int i=1;i<=操作数;++i)
2 {
3     while(已经建了p个<a[i].time){建树(++p);}
4     操作:加或减
5 }

因为我之后建的树会复制前面的树的值,而前面的树的操作都是已经做完了的,然后这个操作是2*m+n。

当然这个也被dalao嘲讽了。。

然后有一个东西要考虑(我就是错了这个)

就是你查询到叶子结点的时候,它的任务数可能会比你剩下要查的个数要大,这样你就不需要取走全部了。。似乎是一个很显然的事情但我当时做却没想到。

  1 #include <iostream>
  2 #include <cstdio>
  3 #include <cstring>
  4 #include <cstdlib>
  5 #include <algorithm>
  6 #define N (100000+5)
  7 #define ll long long
  8 using namespace std;
  9 inline ll read()
 10 {
 11     char ch=getchar();ll kin=1,gi=0;
 12     while(ch>‘9‘||ch<‘0‘){if(ch==‘-‘)kin=-1;ch=getchar();}
 13     while(ch>=‘0‘&&ch<=‘9‘){gi=gi*10+ch-48;ch=getchar();}
 14     return kin*gi;
 15 }
 16 struct tree
 17 {
 18     ll num;
 19     ll simple;
 20     ll son[2];
 21     ll l,r,fl;
 22 }d[5000005];
 23 struct naive
 24 {
 25     ll nic;
 26     ll st;
 27     bool fl;
 28 }ni[N*2];
 29 bool cmp(naive x,naive y)
 30 {
 31     return x.st<y.st;
 32 }
 33 ll n,m,siz,rt[N];
 34 ll sot[N],trl[N],kiz,fis,trik;
 35 ll pre=1,lis[N],ra,rig;
 36 void make(ll,ll,bool);
 37 ll query(ll,ll);
 38 void build(ll,ll,ll);
 39 void rut(ll);
 40 ll mmid(ll x)
 41 {
 42     ll l=1,r=kiz,res=0;
 43     while(l<=r)
 44     {
 45         ll mid=(l+r)>>1;
 46         if(trl[mid]<=x){l=mid+1;res=mid;}
 47         else r=mid-1;
 48     }
 49     return res;
 50 }
 51 int main()
 52 {
 53     m=read();n=read();
 54     for(ll i=1;i<=m;++i)
 55     {
 56
 57         ni[++trik].st=read();ni[trik].fl=1;
 58         ni[++trik].st=read()+1;ni[trik].fl=0;
 59         ni[trik-1].nic=ni[trik].nic=read();
 60         sot[i]=ni[trik].nic;
 61     }
 62     sort(sot+1,sot+m+1);
 63     sort(ni+1,ni+trik+1,cmp);
 64     for(ll i=1;i<=m;++i)if(sot[i]!=sot[i-1])trl[++kiz]=sot[i];
 65     for(ll i=1;i<=trik;++i)
 66     {
 67         if(ni[i].st>n)break;
 68         while(fis<ni[i].st){rut(++fis);}
 69         ll rik=mmid(ni[i].nic);
 70         make(ni[i].st,rik,ni[i].fl);
 71     }
 72     while(fis<n){rut(++fis);}
 73     for(ll i=1;i<=n;++i)
 74     {
 75         ll sec=read();
 76         ll a,b,c,k;
 77         a=read();b=read();c=read();
 78         k=(a*pre+b)%c+1;
 79         printf("%lld\n",pre=query(sec,k));
 80     }
 81     return 0;
 82 }
 83 ll query(ll x,ll y)
 84 {
 85     ll nw=rt[x],res=0;
 86     y=min(y,d[nw].simple);
 87     while(1)
 88     {
 89         if(y==0)break;
 90         if(d[nw].l==d[nw].r&&d[nw].simple>y){res+=trl[d[nw].l]*y;break;}
 91         if(d[nw].simple<=y){res+=d[nw].num;break;}
 92         if(d[d[nw].son[0]].simple<=y) y-=d[d[nw].son[0]].simple,res+=d[d[nw].son[0]].num,nw=d[nw].son[1];
 93         else nw=d[nw].son[0];
 94     }
 95     return res;
 96 }
 97 void make(ll x,ll num,bool p)
 98 {
 99     ll nw=rt[x];bool f;
100     while(d[nw].l!=d[nw].r)
101     {
102         if(p)
103         {d[nw].num+=trl[num];d[nw].simple++;}
104         else
105         {d[nw].num-=trl[num];d[nw].simple--;}
106         f=(num>(d[nw].l+d[nw].r)>>1);
107         if(d[d[nw].son[f]].fl!=x)
108         {
109             d[++siz]=d[d[nw].son[f]];
110             d[nw].son[f]=siz;
111             d[siz].fl=x;
112         }
113         nw=d[nw].son[f];
114     }
115         if(p)
116         {d[nw].num+=trl[num];d[nw].simple++;}
117         else
118         {d[nw].num-=trl[num];d[nw].simple--;}
119 }
120 void rut(ll p)
121 {
122     ll x;
123     x=rt[p]=++siz;
124     d[x].l=1;d[x].r=kiz;d[x].fl=1;
125     if(x>1)
126     {
127         d[rt[p]]=d[rt[p-1]];
128         d[rt[p]].son[0]=d[rt[p-1]].son[0];
129         d[rt[p]].son[1]=d[rt[p-1]].son[1];
130     }
131     else
132     {
133         d[x].son[0]=++siz;
134         build(d[x].son[0],1,(kiz+1)>>1);
135         d[x].son[1]=++siz;
136         build(d[x].son[1],((kiz+1)>>1)+1,kiz);
137     }
138 }
139 void build(ll x,ll l,ll r)
140 {
141     d[x].l=l;d[x].r=r;d[x].fl=1;
142     if(l!=r)
143     {
144         d[x].son[0]=++siz;
145         build(siz,l,(l+r)>>1);
146         d[x].son[1]=++siz;
147         build(siz,((l+r)>>1)+1,r);
148     }
149 }

bzoj3932

时间: 2024-09-30 15:36:59

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

【BZOJ3110】【Zjoi2013】K大数查询 树套树 权值线段树套区间线段树

#include <stdio.h> int main() { puts("转载请注明出处谢谢"); puts("http://blog.csdn.net/vmurder/article/details/43020009"); } 题解: 外层权值线段树,内层区间线段树可解. 权值都是1~n,就不用离散化了. 我写了标记永久化. 其它心得神马的: 天生对树形数据结构无爱. 第一次写树套树,终于知道是怎么回事了. (只针对本题) 就是外层每个点都表示了一段

[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,眼查,无果,跟踪,无果. 拍了几组小数

【BZOJ2653】middle,主席树(非权值线段树)维护区间01信息+二分答案

传送门 写在前面:虽然这是一道我再也不想写的题目,但很好很有价值 思路: cxlove大神: 要求中位数最大,首先二分中位数,然后判断可行不可行. 判断X可行不可行,对于区间内的数,凡是>=X的标为1,否则为-1.这样的话,求一次最大区间和 如果大于等于0,则说明可行. 这要求我们不能像之前那样建立权值线段树的主席树(区间即为权值)了,而是以权值为下标,维护区间[1,n]的信息,可能有点拗口,这里就理解是我们平常写的普通线段树好了,只是这里是n棵由于根的不同而信息不同的线段树 具体实现 对于题目

HDU6621 K-th Closest Distance 第 k 小绝对值(主席树(统计范围的数有多少个)+ 二分 || 权值线段树+二分)

题意:给一个数组,每次给 l ,r, p, k,问区间 [l, r] 的数与 p 作差的绝对值的第 k 小,这个绝对值是多少 分析:首先我们先分析单次查询怎么做: 题目给出的数据与多次查询已经在提示着我们在用数据结构去解决这个问题,对于常见的处理区间的数据结构首选线段树啦: 我觉得这道题的关键在于此:我们需要去二分答案ans,  为什么呢? 我们这样观察 ,对于 | p-a[i] | <= ans  等于 p-ans<=a[i] <=p+ans   那问题就转化为查询[L,R] 区间里面

权值线段树&amp;&amp;可持久化线段树&amp;&amp;主席树

权值线段树 顾名思义,就是以权值为下标建立的线段树. 现在让我们来考虑考虑上面那句话的产生的三个小问题: 1. 如果说权值作为下标了,那这颗线段树里存什么呢? ----- 这颗线段树中, 记录每个值出现的次数 2.权值很大怎么办?数组空间不够啊 ----- 可以先离散化,再记录 3.那权值线段树到底是用来干嘛的呢? ----- 可以快速求出第k小值(其实主要还是为了主席树做铺垫啦) 那第k小值该怎么求呢??? 从树根依次往下 若当前值K大于左儿子的值,则将K-=左儿子的值,然后访问右儿子 若当前

【bzoj3065】带插入区间K小值 替罪羊树套权值线段树

题目描述 从前有n只跳蚤排成一行做早操,每只跳蚤都有自己的一个弹跳力a[i].跳蚤国王看着这些跳蚤国欣欣向荣的情景,感到非常高兴.这时跳蚤国王决定理性愉悦一下,查询区间k小值.他每次向它的随从伏特提出这样的问题: 从左往右第x个到第y个跳蚤中,a[i]第k小的值是多少.这可难不倒伏特,他在脑袋里使用函数式线段树前缀和的方法水掉了跳蚤国王的询问.这时伏特发现有些跳蚤跳久了弹跳力会有变化,有的会增大,有的会减少.这可难不倒伏特,他在脑袋里使用树状数组套线段树的方法水掉了跳蚤国王的询问.(orz 主席

P2617 Dynamic Rankings (动态开点权值线段树 + 树状数组)

题意:带修求区间k小 题解:回忆在使用主席树求区间k小时 利用前缀和的思想 既然是前缀和 那么我们可以使用更擅长维护前缀和的树状数组 但是这里每一颗权值线段树就不是带版本的 而是维护数组里i号点的权值信息 所以实际上并不是主席树 每一棵和前面一棵并没有共用结点 对于一次修改操作 我们先删去这个点的原信息 再更新进去 树状数组上的点一起跳 可能看代码比较好理解一点 这个方法限制性也很强 必须离线 #include <bits/stdc++.h> using namespace std; cons