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

欢迎访问~原文出处——博客园-zhouzhendong

去博客园看该题解


题目传送门 - BZOJ3932


题意概括

  电脑有N个任务需要执行,任务i在li到ri时正在工作,优先级为p。 现在给出M个询问,每个询问给出一个时间点xi和一个数ki。问在xi这个时间点时,所有正在工作的任务中优先级从小到大排列,前ki个的优先级之和是多少。 强制在线。 N<=100 000,M<=100 000


 

题解

  用差分的思想,在Li的地方加,在Ri的地方减。

  然后就是裸的主席树。

  有坑。

  这题细节丧病。

  首先,我把n和m反着写,然后还以为时间点是n(我的n),事实上是我的m。

  其次,还会出现同一个时间点多个事件,要考虑,所以对于长度为1的区间,要sum/size*k

  当然,事情还没有结束。

  size有可能是0,要特判。


 

代码

#include <cstring>
#include <algorithm>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <vector>
using namespace std;
typedef long long LL;
const int N=100005;
int n,m,Ha[N],hs;
vector <int> tz[N];
struct Task{
	int L,R,P;
	void Read(){
		scanf("%d%d%d",&L,&R,&P);
	}
}t[N];
void LSH(){
	int hs_=1;
	sort(Ha+1,Ha+hs+1);
	for (int i=2;i<=hs;i++)
		if (Ha[i]!=Ha[i-1])
			Ha[++hs_]=Ha[i];
	hs=hs_;
}
const int S=N*4*20;
int ls[S],rs[S],size[S],total,root[N];
LL sum[S];
int find(int v){
	return lower_bound(Ha+1,Ha+hs+1,v)-Ha;
}
void build(int &rt,int L,int R){
	rt=++total;
	if (L==R)
		return;
	int mid=(L+R)>>1;
	build(ls[rt],L,mid);
	build(rs[rt],mid+1,R);
}
void add(int prt,int &rt,int L,int R,int pos,LL v,int op){
	if (!rt||rt==prt)
		rt=++total,sum[rt]=sum[prt],size[rt]=size[prt];
	sum[rt]+=v,size[rt]+=op;
	if (L==R)
		return;
	int mid=(L+R)>>1;
	if (!ls[rt])
		ls[rt]=ls[prt];
	if (!rs[rt])
		rs[rt]=rs[prt];
	if (pos<=mid)
		add(ls[prt],ls[rt],L,mid,pos,v,op);
	else
		add(rs[prt],rs[rt],mid+1,R,pos,v,op);
}
LL query(int rt,int L,int R,int k){
	if (L==R){
		k=min(k,size[rt]);
		if (size[rt]==0)
			return 0;
		return sum[rt]*k/size[rt];
	}
	int Lz=size[ls[rt]];
	int mid=(L+R)>>1;
	if (Lz>=k)
		return query(ls[rt],L,mid,k);
	else
		return sum[ls[rt]]+query(rs[rt],mid+1,R,k-Lz);
}
int main(){
	scanf("%d%d",&n,&m);
	for (int i=1;i<=n;i++){
		t[i].Read();
		Ha[i]=t[i].P;
	}
	hs=n;
	LSH();
	for (int i=1;i<=m+1;i++)
		tz[i].clear();
	for (int i=1;i<=n;i++){
		tz[t[i].L].push_back(i);
		tz[t[i].R+1].push_back(i);
		t[i].P=find(t[i].P);
	}
	total=0;
	build(root[0],1,hs);
	for (int i=1;i<=m;i++){
		root[i]=root[i-1];
		for (int j=0;j<tz[i].size();j++){
			int k=tz[i][j];
			if (t[k].L==i)
				add(root[i-1],root[i],1,hs,t[k].P,Ha[t[k].P],1);
			else
				add(root[i-1],root[i],1,hs,t[k].P,-Ha[t[k].P],-1);
		}
	}
	LL pre=1;
	for (int i=1;i<=m;i++){
		int x,A,B,C,k;
		scanf("%d%d%d%d",&x,&A,&B,&C);
		k=(pre*A+B)%C+1;
		printf("%lld\n",pre=query(root[x],1,hs,k));
	}
	return 0;
}

  

posted @ 2017-12-18 23:04  zzd233  阅读(259)  评论(0编辑  收藏  举报