洛谷 P3168 [CQOI2015]任务查询系统 解题报告
P3168 [CQOI2015]任务查询系统
题目描述
最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。
超级计算机中的任务用三元组\((S_i,E_i,P_i)\)描述,\((S_i,E_i,P_i)\)表示任务从第\(S_i\)秒开始,在第\(E_i\)秒后结束(第\(S_i\)秒和\(E_i\)秒任务也在运行),其优先级为\(P_i\)。同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同。
调度系统会经常向查询系统询问,第\(X_i\)秒正在运行的任务中,优先级最小的\(K_i\)个任务(即将任务按照优先级从小到大排序后取前\(K_i\)个)的优先级之和是多少。
特别的,如果\(K_i\)大于第\(X_i\)秒正在运行的任务总数,则直接回答第\(X_i\)秒正在运行的任务优先级之和。上述所有参数均为整数,时间的范围在\(1\)到\(n\)之间(包含\(1\)和\(n\))。
输入输出格式
输入格式:
输入文件第一行包含两个空格分开的正整数\(m\)和\(n\),分别表示任务总数和时间范围。
接下来m行,每行包含三个空格分开的正整数\(S_i\)、\(E_i\)和\(P_i(S_i<=E_i)\),描述一个任务。接下来\(n\)行,每行包含四个空格分开的整数\(X_i\)、\(A_i\)、\(B_i\)和\(C_i\),描述一次查询。
查询的参数\(K_i\)需要由公式 \(K_i=1+(A_i*Pre+B_i) \ mod \ C_i\)计算得到。其中\(Pre\)表示上一次查询的结果,对于第一次查询,\(Pre=1\)。
输出格式:
输出共\(n\)行,每行一个整数,表示查询结果。
说明
对于100%的数据,\(1<=m,n,S_i,E_i,C_i<=100000\),\(0<=A_i,B_i<=100000\),\(1<=P_i<=10000000\),\(X_i\)为\(1\)到\(n\)的一个排列
时空范围:2sec,256mb
化简模型,给出\(m\)个三元组\((s,e,p)\)
询问\((x,k)\)为满足\(s \le x \le e\)的三元组的前\(k\)大\(p\)值之和,强制在线
一看是一个偏序类题目,我们可以多维数据结构暴力嵌套,这个题最多允许\(log^2\),又有第\(k\)大询问,自然的想到主席树降维
使用树状树状套主席树求解
其中树状树状的区间代表从大到小排序的\(E_i\)
树状树状的每个区间放对应的一群线段树,我们先对区间按\(S_i\)从小到大排序,然后按这个顺序建主席树就行了
主席树的节点存离散(不离散似乎也过了)的\(p_i\)值,注意维护一下区间和
查询的时候,在每个树状数组对应的主席树上一起二分即可,注意重复的元素
Code
#include <cstdio>
#include <algorithm>
#include <vector>
#define ll long long
using namespace std;
const int N=1e5+10;
struct node
{
int s,t,p;
bool friend operator <(node n1,node n2){return n1.t>n2.t;}
}rask[N];
struct RT
{
int s,now;
RT(){}
RT(int s,int now){this->s=s,this->now=now;}
bool friend operator <(RT n1,RT n2){return n1.s<n2.s;}
}rt;
vector <RT> root[N];
int cnt[N*244],ch[N*244][2],tot,n,m,mxx;ll sum[N*244];
int max(int x,int y){return x>y?x:y;}
#define ls ch[now][0]
#define rs ch[now][1]
#define ols ch[las][0]
#define ors ch[las][1]
void update(int now)
{
sum[now]=sum[ls]+sum[rs];
cnt[now]=cnt[ls]+cnt[rs];
}
int build(int las,int l,int r,int pos)
{
int now=++tot;
if(l==r)
{
cnt[now]=cnt[las]+1;
sum[now]=1ll*cnt[now]*l;
return now;
}
int mid=l+r>>1;
if(pos<=mid)
{
ls=build(ols,l,mid,pos);
rs=ors;
}
else
{
ls=ols;
rs=build(ors,mid+1,r,pos);
}
update(now);
return now;
}
void init()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
scanf("%d%d%d",&rask[i].s,&rask[i].t,&rask[i].p),mxx=max(mxx,rask[i].p);
sort(rask+1,rask+1+m);
for(int i=1;i<=m;i++)
{
for(int j=i-(i&-i)+1;j<=i;j++)
{
rt=RT(rask[j].s,j);
root[i].push_back(rt);
}
sort(root[i].begin(),root[i].end());
for(int las=0,j=0;j<root[i].size();j++)
las=root[i][j].now=build(las,1,mxx,rask[root[i][j].now].p);
}
}
ll query(int x,int pos,int k)//时间,前pos可查,第k值
{
int now[50],p=0;
for(int i=pos;i;i-=i&-i)
{
RT t=RT(x,0);
int j=upper_bound(root[i].begin(),root[i].end(),t)-root[i].begin()-1;
now[++p]=root[i][j].now;
}
int l=1,r=mxx;ll ans=0;
while(l<r)
{
int mid=l+r>>1,s=0;
for(int i=1;i<=p;i++) s+=cnt[ch[now[i]][0]];
if(s>=k)
{
for(int i=1;i<=p;i++) now[i]=ch[now[i]][0];
r=mid;
}
else
{
for(int i=1;i<=p;i++) ans+=sum[ch[now[i]][0]],now[i]=ch[now[i]][1];
l=mid+1,k-=s;
}
}
int cnt0=0;
for(int i=1;i<=p;i++) cnt0+=cnt[now[i]];
ans+=1ll*l*min(cnt0,k);
return ans;
}
void work()
{
ll pre=1;
for(int pos,x,a,b,c,k,i=1;i<=n;i++)
{
scanf("%d%d%d%d",&x,&a,&b,&c);
k=(a*(int)(pre%(1ll*c))+b)%c+1;
node t={0,x,0};
pos=upper_bound(rask+1,rask+1+m,t)-rask-1;
printf("%lld\n",pre=query(x,pos,k));
}
}
int main()
{
init(),work();
return 0;
}
然而,我们注意到这个问题有这样一个暴力
对操作,我们可以把每个对应位置上都加上这个优先级,并用权值线段树维护
然后查询时,直接进入对应位置的权值线段树查询即可
而事实上,我们发现这是对每个位置有一个区间加,我们可以采用差分数组的思想
把三元组\((s,e,p)\)的\(s\)位置的\(p\)值\(+1\),把\(e+1\)位置\(p\)值\(-1\)(这里\(p\)值在对于位置的权值线段树上)
然后我们查询的时候,就求这些权值线段树的前缀和就可以了
这不就是主席树干的事情吗
于是乎问题就可以直接用主席树做了
Code:
#include <cstdio>
#include <algorithm>
#define ll long long
using namespace std;
const int N=1e5+10;
struct node{int s,e,p;}rask[N];
int a[N];
int cnt[N*100],ch[N*100][2],root[N],tot,n,m,num;ll sum[N*100];
#define ls ch[now][0]
#define rs ch[now][1]
void updata(int now)
{
sum[now]=sum[ls]+sum[rs];
cnt[now]=cnt[ls]+cnt[rs];
}
void build(int &now,int l,int r,int pos,int del)
{
if(!now) now=++tot;
if(l==r)
{
cnt[now]+=del;
sum[now]=1ll*cnt[now]*a[l];
return;
}
int mid=l+r>>1;
if(pos<=mid)
build(ls,l,mid,pos,del);
else
build(rs,mid+1,r,pos,del);
updata(now);
}
int rebuild(int x,int y)
{
if(!x||!y) return x+y;
int now=++tot;
sum[now]=sum[x]+sum[y];
cnt[now]=cnt[x]+cnt[y];
ls=rebuild(ch[x][0],ch[y][0]);
rs=rebuild(ch[x][1],ch[y][1]);
return now;
}
void init()
{
scanf("%d%d",&m,&n);
for(int i=1;i<=m;i++)
{
scanf("%d%d%d",&rask[i].s,&rask[i].e,&rask[i].p);
a[i]=rask[i].p;
}
sort(a+1,a+1+m);
++n;
num=unique(a+1,a+1+m)-a-1;
for(int i=1;i<=m;i++)
{
rask[i].p=lower_bound(a+1,a+1+num,rask[i].p)-a;
build(root[rask[i].s],1,num,rask[i].p,1);
build(root[rask[i].e+1],1,num,rask[i].p,-1);
}
for(int i=1;i<=n;i++)
root[i]=rebuild(root[i-1],root[i]);
}
ll query(int now,int l,int r,int k)
{
if(l==r)
return 1ll*a[l]*min(k,cnt[now]);
int mid=l+r>>1;
if(cnt[ls]>=k) return query(ls,l,mid,k);
else return sum[ls]+query(rs,mid+1,r,k-cnt[ls]);
}
void work()
{
ll pre=1;
for(int x,a,b,c,k,i=1;i<n;i++)
{
scanf("%d%d%d%d",&x,&a,&b,&c);
k=(a*(int)(pre%(1ll*c))+b)%c+1;
printf("%lld\n",pre=query(root[x],1,num,k));
}
}
int main()
{
init(),work();
return 0;
}
2018.9.13
洛谷 P3168 [CQOI2015]任务查询系统 解题报告的更多相关文章
- 洛谷P3168 [CQOI2015]任务查询系统 [主席树,差分]
题目传送门 任务查询系统 题目描述 最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分.超级计算机中的任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任 ...
- ●洛谷P3168 [CQOI2015]任务查询系统
题链: https://www.luogu.org/problemnew/show/P3168题解: 主席树 强制在线? 那就直接对每一个前缀时间建一个线段树(可持久化线段树),线段树维护优先度权值. ...
- 洛谷P3168 [CQOI2015]任务查询系统
#include<cstdio> #include<cstdlib> #include<algorithm> #include<cstring> #in ...
- 洛谷 P3171 [CQOI2015]网络吞吐量 解题报告
P3171 [CQOI2015]网络吞吐量 题目描述 路由是指通过计算机网络把信息从源地址传输到目的地址的活动,也是计算机网络设计中的重点和难点.网络中实现路由转发的硬件设备称为路由器.为了使数据包最 ...
- P3168 [CQOI2015]任务查询系统
题目地址:P3168 [CQOI2015]任务查询系统 主席树的模板题 更模板的在这儿:P3834 [模板]可持久化线段树 1(主席树) 形象的说,P3834是"单点修改,区间查询" ...
- bzoj3932 / P3168 [CQOI2015]任务查询系统(主席树+差分)
P3168 [CQOI2015]任务查询系统 看到第k小,就是主席树辣 对于每一段任务(a,b,k),在版本a的主席树+k,版本b+1的主席树-k 同一时间可能有多次修改,所以开个vector存操作, ...
- 洛谷_Cx的故事_解题报告_第四题70
1.并查集求最小生成树 Code: #include <stdio.h> #include <stdlib.h> struct node { long x,y,c; ...
- 洛谷$P$3168 任务查询系统 $[CQOI2015]$ 主席树
正解:主席树 解题报告: 传送门! 首先考虑如果是单点修改,那就是个线段树板子嘛$QwQ$ 然后现在是区间修改,对于区间修改,显然就考虑差分下,就变成单点修改辣$QwQ$ 同时单点查询前$k$小也就变 ...
- 洛谷 P2317 [HNOI2005]星际贸易 解题报告
P2317 [HNOI2005]星际贸易 题目描述 输入输出格式 输入格式: 输出格式: 如果可以找到这样的方案,那么输出文件output.txt中包含两个整数X和Y.X表示贸易额,Y表示净利润并且两 ...
随机推荐
- 洛谷P4316 绿豆蛙的归宿(期望)
题意翻译 「Poetize3」 题目背景 随着新版百度空间的上线,Blog宠物绿豆蛙完成了它的使命,去寻找它新的归宿. 题目描述 给出一个有向无环图,起点为1终点为N,每条边都有一个长度,并且从起点出 ...
- vim指令,快捷键汇总
Vim 命令.操作.快捷键全集 命令历史 以:和/开头的命令都有历史纪录,可以首先键入:或/然后按上下箭头来选择某个历史命令. 启动vim 在命令行窗口中输入以下命令即可 vim 直接启动vim vi ...
- python核心编程2 第五章 练习
5-2 运算符(a) 写一个函数,计算并返回两个数的乘积(b) 写一段代码调用这个函数,并显示它的结果 def product(x, y): return x * y if __name__ == ' ...
- Redhat 6.4 linux系统不重启识别热添加的硬盘方法
1.1 选择虚拟机添加一块硬盘 1.2 查看系统当前磁盘信息 [root@zhongyi-test ~]# ls -l /dev/sd* brw-rw----. 1 root disk 8 ...
- python__系统 : 异步实现以及GIL
创建进程的方式中有个 callback ,也就是回调. 看代码: from multiprocessing import Pool import time import os def test(): ...
- http网络协议 学习摘要
一:HTTP协议状态码 状态码主要用于描述当客户端向服务器发送请求时的返回结果,标记服务端的处理是否正常,通知出现的错误等工作. 状态码整体分为五大类: 1开头的状态码:信息类状态码,主要接收请求,表 ...
- proteus中蜂鸣器不响的原因
本文参考自https://blog.csdn.net/gin_love/article/details/51168369 此网站.在用proteus仿真报警电路时,发现蜂鸣器不响.后在网上找了 ...
- Android 时间计算工具 通用类TimeUtil
1.整体分析 1.1.源代码如下,可以直接Copy. public class TimeUtil { private static final String TAG = "TimeUtil& ...
- build dynamic libraries for iOS and load them at runtime
编译了libmt.dylib, 和 test 程序调用,均正常.在xcode中显示调用正常,隐式调用则出现问题. 提示 dyld: Library not loaded. 即使存在在/usr/lib/ ...
- windows 定时任务 - 定时关机
添加定时关机,刚好可以利用windows定时任务 [开始]->[控制面板]->[任务计划]->[添加任务计划] 1.找到 shutdown.exe 设置每天执行 2.设置晚上10点 ...