1. 程式人生 > >洛谷 P3168 [CQOI2015]任務查詢系統 主席樹

洛谷 P3168 [CQOI2015]任務查詢系統 主席樹

P3168

這個主席樹的題很多人寫題解,但是我想寫一份程式碼足夠簡潔的題解,思路很簡單,對於每個區間 l r p,我們用差分陣列,分別記錄左端點和右端點即可,如果不會差分陣列建議去刷一下南陽oj士兵殺敵5,差分陣列模板題,然後差分陣列的字首和就是每個時間點所含有的任務資訊了,接下來用主席樹模板即可。

#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=2e5+10;
typedef long long ll;
struct node
{
	int pos,k,v;
	bool operator<(const node& t)const
	{
		return pos<t.pos;
	}
}a[maxn];
int b[maxn],rt[maxn],ls[maxn*20],rs[maxn*20],sum[maxn*20];
ll ans[maxn*20];
int cnt=0,sz=0;
void up(int pre,int &o,int l,int r,int k,int v)
{
	o=++cnt;
	sum[o]=sum[pre]+v;
	ans[o]=ans[pre]+v*b[k];
	ls[o]=ls[pre];
	rs[o]=rs[pre];
	if(l==r)return;
	int m=(l+r)/2;
	if(k<=m)up(ls[pre],ls[o],l,m,k,v);
	else up(rs[pre],rs[o],m+1,r,k,v);
}
ll qu(int o,int l,int r,int k)
{
	if(k>=sum[o])return ans[o];
	if(l==r)return 1ll*b[l]*k;
	int m=(l+r)/2,res=sum[ls[o]];
	if(k<=res)return qu(ls[o],l,m,k);
	else return ans[ls[o]]+qu(rs[o],m+1,r,k-res);
}
int main()
{
	int n,m,l,r,x;
	scanf("%d%d",&n,&m);
	for(int i=1;i<=n;i++)
	{
		scanf("%d%d%d",&l,&r,&b[i]);
		a[i].pos=l,a[i].k=b[i],a[i].v=1;
		a[i+n].pos=r+1,a[i+n].k=b[i],a[i+n].v=-1;
	}
	sort(b+1,b+1+n);
	sz=unique(b+1,b+1+n)-b-1;
	sort(a+1,a+1+2*n);
	for(int i=1;i<=2*n;i++)a[i].k=lower_bound(b+1,b+1+sz,a[i].k)-b;
	for(int i=1;i<=2*n;i++)
	up(rt[a[i-1].pos],rt[a[i].pos],1,sz,a[i].k,a[i].v);
	for(int i=1;i<=n;i++)if(!rt[i])rt[i]=rt[i-1];
	ll pre=1,A,B,C;
	for(int i=1;i<=m;i++)
	{
		scanf("%d%lld%lld%lld",&x,&A,&B,&C);
		int k=1+(A*pre+B)%C;
		printf("%lld\n",pre=qu(rt[x],1,sz,k)); 
	}
}