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]\) 之间。
本题强制在线。
【数据范围】
对于 \(100\%\) 的数据,\(1\le m,n,c_i \le 10 ^ 5\),\(0 \le a _ i, b _ i \le 10 ^ 5\),\(1\leq s_i\leq e_i\leq n\),\(1\le p_i \le 10^7\),\(x_i\) 为 \(1\) 到 \(n\) 的一个排列。
Solution:
维护一颗主席树,线段树的下标代表优先级(权值),根的下标代表时间
对于每个任务,做一个差分,在 \(s_i\) 处的线段树上加一个 \(p_i\) ,在 \(e_{i+1}\) 处减掉 \(p_i\)
挂完所有任务之后直接查询就好了,十分模板,十分好上手啊 😃
Code:
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+10;
int n,m,num,tot;
int a[N],b[N],root[N<<6];
long long ans=1;
struct tree {
long long sum;
int cnt,ls,rs;
}t[N<<6];
vector<int>be[N],ed[N];
void update(int &x,int l,int r,int pre,int pos,int v)
{
x=++tot; t[x]=t[pre];
t[x].cnt+=v, t[x].sum+=1ll*v*b[pos];
if(l==r) return;
int mid=(l+r)>>1;
if(pos<=mid) update(t[x].ls,l,mid,t[pre].ls,pos,v);
else update(t[x].rs,mid+1,r,t[pre].rs,pos,v);
}
long long query(int u,int l,int r,int k)
{
int num=t[t[u].ls].cnt;
if(l==r) return t[u].sum/(1ll*t[u].cnt)*1ll*k;
int mid=(l+r)>>1;
if(k<=num) return query(t[u].ls,l,mid,k);
else return query(t[u].rs,mid+1,r,k-num)+t[t[u].ls].sum;
}
int main(){
//freopen("q.in","r",stdin);
//freopen("queryans.out","w",stdout);
cin>>m>>n;
for(int i=1,x,y;i<=m;i++)
{
scanf("%d%d%d",&x,&y,&a[i]);
b[i]=a[i];
be[x].push_back(i), ed[y+1].push_back(i);
}
sort(b+1,b+1+m);
int num=unique(b+1,b+1+m)-b-1;
for(int i=1;i<=n;i++)
{
root[i]=root[i-1];
for(int j=0;j<be[i].size();j++)
{
int p=lower_bound(b+1,b+1+num,a[be[i][j]])-b;
update(root[i],1,num,root[i],p,1);
}
for(int j=0;j<ed[i].size();j++)
{
int p=lower_bound(b+1,b+1+num,a[ed[i][j]])-b;
update(root[i],1,num,root[i],p,-1);
}
}
long long ans=1;
for(int i=1,a,b,c,k,x;i<=n;i++)
{
scanf("%d%d%d%d",&x,&a,&b,&c);
k=(1ll*a*ans+b)%c+1;
if(k>t[root[x]].cnt) ans=t[root[x]].sum;
else ans=query(root[x],1,num,k);
printf("%lld\n",ans);
}
return 0;
}

浙公网安备 33010602011771号