P3168 [CQOI2015]任务查询系统

题意描述:

洛谷

每一个任务有三个属性: \(s,t,w\) , 表示这个任务会在 \(s-t\) 这一段时间内运行,优先度为 \(w\) .

有 \(q\) 组询问,每次询问你 第 \(x\) 秒运行的任务的优先度前 \(k\) 小的任务的优先度之和。

数据范围: \(n,m\leq 10^5 , w\leq 10^9\)

solution:

有一个很 \(naive\) 的想法,对于每个任务把他 插入到 \(s-t\) 当中, 对于每一时刻开个权值线段树,权值为每个任务的优先度,每次询问就相当于在权值线段树上找前 \(k\) 小的数的和。

暴力插的复杂度肯定不对,考虑怎么优化一下。

我们维护的是每个时刻优先度为 \(w\) 的任务的个数,那么一个任务对 \(s-t\) 会有 \(1\) 的贡献。

区间加 \(1\) ,很容易想到差分, 然后维护一下前缀和。

拿主席树来维护一下,每次询问就在主席树上二分查找就好了。

注意:每次修改都要新建一个版本,不然会导致节点的信息出错。

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<vector>
using namespace std;
#define int long long
const int N = 2e5+10;
const int inf = 1e7+10;
int n,m,tot,s,t,p,x,a,b,c,k,cnt,last = 1,rt[N<<2],B[N];
vector<pair<int,int> > v[N];
struct Tree
{
	int lc,rc,siz,sum;
}tr[40000000];
inline int read()
{
	int s = 0,w = 1; char ch = getchar();
	while(ch < '0' || ch > '9'){if(ch == '-') w = -1; ch = getchar();}
	while(ch >= '0' && ch <= '9'){s = s * 10 + ch - '0'; ch = getchar();}
	return s * w;
}
void up(int o)
{
	tr[o].siz = tr[tr[o].lc].siz + tr[tr[o].rc].siz;
	tr[o].sum = tr[tr[o].lc].sum + tr[tr[o].rc].sum;
}
int insert(int &o,int last,int l,int r,int x,int val)
{
	o = ++tot;
	if(l == r)
	{
		tr[o].siz = tr[last].siz + val;
		tr[o].sum = tr[last].sum + val * B[l];
		return o;
	}
	tr[o].lc = tr[last].lc;
	tr[o].rc = tr[last].rc;
	int mid = (l + r)>>1;
	if(x <= mid) tr[o].lc = insert(tr[o].lc,tr[last].lc,l,mid,x,val);
	if(x > mid) tr[o].rc = insert(tr[o].rc,tr[last].rc,mid+1,r,x,val);
	up(o);
	return o;
}
int query(int o,int l,int r,int k)
{
	if(!o) return 0;
	if(l == r && tr[o].siz >= k) return k * B[l];
	else if(l == r) return tr[o].sum;
	if(tr[o].siz <= k) return tr[o].sum;
	int mid = (l + r)>>1;
	if(tr[tr[o].lc].siz >= k) return query(tr[o].lc,l,mid,k);
	else return tr[tr[o].lc].sum + query(tr[o].rc,mid+1,r,k-tr[tr[o].lc].siz);
}
signed main()
{
	m = read(); n = read();
	for(int i = 1; i <= m; i++)
	{
		s = read(); t = read(); p = read();
		B[++cnt] = p;
		v[s].push_back(make_pair(p,1));
		v[t+1].push_back(make_pair(p,-1));
	}
	sort(B+1,B+cnt+1);
	int num = unique(B+1,B+cnt+1)-B-1;
	for(int i = 1; i <= n; i++) 
	{
		rt[i] = rt[i-1];
		for(int j = 0; j < v[i].size(); j++)
		{
			int pos = lower_bound(B+1,B+num+1,v[i][j].first)-B;
			rt[i] = insert(rt[i],rt[i],1,num,pos,v[i][j].second);
		}
	}
	for(int i = 1; i <= n; i++)
	{
		x = read(); a = read(); b = read(); c = read();
		k = 1 + (a * last % c + b) % c;
		last = query(rt[x],1,num,k);
		printf("%lld\n",last);
	}
	return 0;
}

上一篇:a_lc_完成所有工作的最短时间(暴搜 / 状压)


下一篇:网易一面面筋,兴华倒了