P3168 [CQOI2015]任务查询系统「题解」-可持久化线段树

「P3168 [CQOI2015]任务查询系统」--传送门

大致题意

给你\(m\)条信息,即一个优先级为\(p_i\)的任务,处理时间为\(l_i~r_i\)
给你\(n\)条询问,每条询问:在\(x\)时刻优先级前\(K\)小的任务\(p\)的总和为多少。
\(1<=n,m<=10^5,1<=p_i<=10^7\)

题解

\(n,m\)这样的范围,大概是\(O(nlogn0)\)吧,并且有前\(k\)小,而且是对于一个序列的操作,同时他问的是\(x\)时刻,所以我们要知道每一个时刻树的版本,为了节省内存,要用可持久化线段树去维护值域
我们可以将每一时刻作为一个版本,每一个版本的树中包含这一时刻正在进行的任务及其优先级
我们可以用差分的思想,若一个优先级为\(p_i\)的任务在\([l,r]\)区间内执行,我们就可以在\(l\)版本时加上数\(p_i\),\(l~r\)版本之间不动它,使其依次向后承接/转移,到了\(r+1\)版本将其删除即可。
对于一个版本,我们用主席树维护值域区间\([1,10^7]\),也就是优先级的值域,从而在求前\(k\)小的时候能够二分确定位置。可以离散化,但我懒得写了。
我们对于树上节点不仅要维护一个\(size\)从而确定前\(k\)小的范围,还要维护一个\(val\)去求和,每次向该节点及其子节点(如果不是叶子节点)加数的时候,\(val\)都要加上该数的值,删除的话就减去,我们这样就可以用该节点的\(val\)来表示出该节点所代表范围中所有加过数的总和,从而更方便的求出前\(k\)小的和。
查询也跟平时的主席树一样,只不过是个求和而已。
注意细节,访问到叶子节点时,该叶子节点可能size>1,但不选他就不够k个,选他就超过k个,我们要用val/size*k去选出k个。
注意判断:除数不为0。

#include <cstdio>
#include <vector>
#define int long long
using namespace std;
const int maxn=100000+5;
struct Node{
	int lc,rc;
	int siz;
	int val;
};
Node t[maxn*25*2];
int n,m;
int pre=1;
vector<int> a[maxn],b[maxn];
int root[maxn];
int tot;
void Insert(int &rt,int l,int r,int p,int v){
	int pos=++tot;
	t[pos]=t[rt];
	rt=pos;
	t[rt].siz+=v;
	t[rt].val+=v*p;
	if(l==r) return;
	int mid=(l+r)>>1;
	if(p<=mid) Insert(t[rt].lc,l,mid,p,v);
	else Insert(t[rt].rc,mid+1,r,p,v);
}
int Q(int rt,int l,int r,int k){
	if(l==r&&t[rt].siz!=0) return t[rt].val/t[rt].siz*k;// 注意除数为0特判
	else if(l==r) return 0;
	int mid=(l+r)>>1;
	if(t[t[rt].lc].siz>=k) return Q(t[rt].lc,l,mid,k);
	else return t[t[rt].lc].val+Q(t[rt].rc,mid+1,r,k-t[t[rt].lc].siz);
}
signed main(){
//	freopen("1.in","r",stdin);
	scanf("%lld%lld",&m,&n);
	for(int i=1,x,y,z;i<=m;++i){
		scanf("%lld%lld%lld",&x,&y,&z);
		a[x].push_back(z);
		b[y+1].push_back(z);
	}
	for(int i=1;i<=m;++i){
		root[i]=root[i-1];
		for(int j=0;j<a[i].size();++j) Insert(root[i],1,1e7,a[i][j],1);
		for(int j=0;j<b[i].size();++j) Insert(root[i],1,1e7,b[i][j],-1);
	}
	for(int i=1,x,a,b,c;i<=n;++i){
		scanf("%lld%lld%lld%lld",&x,&a,&b,&c);
		pre=Q(root[x],1,1e7,1+(a*pre+b)%c);
		printf("%lld\n",pre);
	}
	return 0;
}

猜你喜欢

转载自www.cnblogs.com/Lour688/p/13366906.html