P3168 [CQOI2015] 任务查询系统题解
看到大佬们都在用主席树写,但是蒟蒻难以理解这样写的原因,于是只好写了个更容易理解的线段树合并。
前置知识
差分(不会差分写这题?)。
离散化。(不会离散化写这题?)。
权值线段树(其实就是线段树维护桶)。
线段树合并(不会的先写这题)。
思路
差分+权值线段树+线段树合并。
题目要求求每一秒权值前
于是想到在每一个时间点开一个权值树,维护任务总数
题目要求区间修改,于是想到利用差分思想。
将
将
最后将权值树按照时间顺序合并,第一秒与第二秒合并,然后将第二秒与第三秒合并,以此类推,即可得到修改之后每一秒中任务的数据(类比差分数组求前缀和得到原数组)。
查询时直接在第
这时有巨佬就要发问了,优先级最大值为
我们来看,任务总数为 离散化应该都会吧。
然后动态开点,只有当某颗权值树上的某个节点被使用到时才开一个节点,这样就不存在浪费空间的问题了。
具体细节看代码。
复杂度分析
每次利用动态开点和离散化,每加入一个新的任务时,只增加至多
每次加入一个任务时至多新开
合并假设将每个端点都与另一个端点合并,时间复杂度与空间复杂度一致,为
查询复杂度 (这个不用过多解释了吧)。
总时间复杂度:
可以通过此题。
代码
#include<bits/stdc++.h>
#define ll long long
#define dd double
#define lson c[id].ls
#define rson c[id].rs
#define mid ((l+r)/2)
using namespace std;
inline ll read(){
ll x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9'){
if(ch=='-'){
f=-1;
}
ch=getchar();
}
while(ch>='0'&&ch<='9'){
x=x*10+ch-'0';
ch=getchar();
}
return x*f;
}
void write(ll x){
if(x<0){
putchar('-');
x=-x;
}
if(x>9){
write(x/10);
}
putchar(x%10+'0');
}
const ll N=1e5+9;
ll b[N],q;//离散化
ll s[N],e[N],a[N];//存储任务信息
ll n,m,pre=1;
ll ccnt;//动态开点
struct NODE{
ll ls,rs;
ll cnt,sum;//任务数,优先级总和
}c[N*50];//权值树
ll root[N];//第i秒对应的权值树的根节点
ll getid(ll x){
return lower_bound(b+1,b+q+1,x)-b;
}
void pu(ll id){//push_up
c[id].cnt=c[lson].cnt+c[rson].cnt;
c[id].sum=c[lson].sum+c[rson].sum;
}
void change(ll &id,ll l,ll r,ll x,ll vel){//某秒优先级为x的任务增加或减少1
if(!id){
id=++ccnt;
}
if(l==r){
c[id].cnt+=vel;
c[id].sum+=b[x]*vel;
return;
}
if(x<=mid){
change(lson,l,mid,x,vel);
}
else{
change(rson,mid+1,r,x,vel);
}
pu(id);
}
ll hebing(ll u,ll v,ll l,ll r){//把v合并到u上
if(u==0||v==0){
return u+v;
}
if(l==r){
c[u].cnt+=c[v].cnt;
c[u].sum+=c[v].sum;
return u;
}
c[u].ls=hebing(c[u].ls,c[v].ls,l,mid);
c[u].rs=hebing(c[u].rs,c[v].rs,mid+1,r);
pu(u);
return u;
}
void cacl(){//合并差分数据得到原数据
for(int i=1;i<=n;i++){//按照时间顺序合并
root[i]=hebing(root[i],root[i-1],1,q);
}
}
ll qu(ll id,ll l,ll r,ll k){//查询某秒优先级最小的k个任务的优先级之和
if(l==r){
if(c[id].cnt>k){
return (c[id].sum/c[id].cnt)*k;//由于叶子节点只表示一种优先级,所以可以算出每个任务的优先级然后乘以k出答案
}
else{
return c[id].sum;
}
}
if(k<=c[lson].cnt){
return qu(lson,l,mid,k);
}
else{
return qu(rson,mid+1,r,k-c[lson].cnt)+c[lson].sum;
}
}
int main(){
m=read();
n=read();
for(int i=1;i<=m;i++){
s[i]=read(),e[i]=read(),a[i]=read();
b[++q]=a[i];
}
sort(b+1,b+q+1);
q=unique(b+1,b+q+1)-b-1;//离散化
for(int i=1;i<=m;i++){
change(root[s[i]],1,q,getid(a[i]),1);
change(root[e[i]+1],1,q,getid(a[i]),-1);//差分思想修改
}
cacl();//线段树合并
for(int i=1;i<=n;i++){
ll x=read(),a=read(),b=read(),c=read();
ll k=1+(a*pre+b)%c;
pre=qu(root[x],1,q,k);
write(pre);
putchar('\n');
}
return 0;
}
本题解已通过 hack,记录。