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; }