BZOJ3932:[CQOI2015]任务查询系统——题解
http://www.lydsy.com/JudgeOnline/problem.php?id=3932
题面源于洛谷
题目描述
最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行),其优先级为Pi。同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同。调度系统会经常向查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个)的优先级之和是多少。特别的,如果Ki大于第Xi秒正在运行的任务总数,则直接回答第Xi秒正在运行的任务优先级之和。上述所有参数均为整数,时间的范围在1到n之间(包含1和n)。
输入输出格式
输入格式:
输入文件第一行包含两个空格分开的正整数m和n,分别表示任务总数和时间范围。接下来m行,每行包含三个空格分开的正整数Si、Ei和Pi(Si<=Ei),描述一个任务。接下来n行,每行包含四个空格分开的整数Xi、Ai、Bi和Ci,描述一次查询。查询的参数Ki需要由公式 Ki=1+(Ai*Pre+Bi) mod Ci计算得到。其中Pre表示上一次查询的结果,对于第一次查询,Pre=1。
输出格式:
输出共n行,每行一个整数,表示查询结果。
输入输出样例
————————————————————————
抄代码一时爽,事后比较火葬场。
查了半个小时发现两个语句反了(晕……
代码于:http://blog.csdn.net/oakley_/article/details/52250622 理解于:http://blog.csdn.net/shiyukun1998/article/details/44910169
!注意!请不要hack我的程序,我知道我抄的代码以及那篇博客的代码的空间复杂度不对,一个主席树的空间复杂度为O(nlogn)级别的,如果不离散化的话是绝对会炸的,所以能过……只能说数据水吧。
我们根据某矩形覆盖的题,想到能否看做在s时刻插入p,在e+1时刻删除p。
那么按照某矩形覆盖的想法,我们分为上下边界,上边界存p,下边界存-p。
根据他们插入/删除的时间排序,之后我们就可以愉快的在p的范围区间内建主席树啦!
Q1:等等,怎么突然就跳到主席树啦?
A1:那这里说一下主席树的想法:在一棵当前时间的主席树上查找区间前k小的数,然后加和即可。!注意!可能有多个任务重合在一个地点上,所以不要忘了加上。
Q2:别忽悠我,只有一棵树的话你岂不是要把前面时间的数也算在内?
A2:是这样的没错,但是因为前面时间的值已经被我们的下边界减掉了,同时于他们的sum和size,所以区间第k小不会搜到他们。
Q3:你的意思是……求k前缀和?
A3:我的理解是这样,但是我的代码实现能力太糟糕了,没有这样写过,很抱歉。
Q4:代码怎么这么不清真?
A4:实在是处于主席树开荒期,所以不可避免的借鉴他人思路,有些时候相比较看题解而言看他们的代码更为清楚一些。
#include<cstdio> #include<queue> #include<cctype> #include<cstring> #include<cmath> #include<vector> #include<algorithm> using namespace std; typedef long long ll; const int N=200010; inline int read(){ int X=0,w=0;char ch=0; while(!isdigit(ch)){w|=ch=='-';ch=getchar();} while(isdigit(ch))X=(X<<3)+(X<<1)+(ch^48),ch=getchar(); return w?-X:X; } struct mission{ int pos; ll p; }scp[N]; inline bool cmp(mission a,mission b){ return a.pos<b.pos; } struct tree{ int l; int r; int size; ll sum; }tr[10000001]; int rt[N],to[N],n,q,pool; ll m; inline void insert(int &y,int &x,int l,int r,ll p){ tr[x=++pool]=tr[y]; if(l==r){ if(p>0)tr[x].size++; else tr[x].size--; tr[x].sum+=p; return; } int mid=(l+r)>>1; if(abs(p)<=mid)insert(tr[y].l,tr[x].l,l,mid,p); else insert(tr[y].r,tr[x].r,mid+1,r,p); tr[x].sum=tr[tr[x].l].sum+tr[tr[x].r].sum; tr[x].size=tr[tr[x].l].size+tr[tr[x].r].size; return; } ll check(ll H,ll k){ ll x=rt[H],l=1,r=m,ans=0; if(tr[x].size<=k){ return tr[x].sum; } while(l<r){ ll mid=(l+r)>>1; if(tr[tr[x].l].size>=k){ r=mid; x=tr[x].l; }else{ l=mid+1; k-=tr[tr[x].l].size; ans+=tr[tr[x].l].sum; x=tr[x].r; } } if(k)ans+=l*k; return ans; } int main(){ n=read(); q=read(); n*=2; for(int i=1;i<=n;i+=2){ scp[i].pos=read(); scp[i+1].pos=read()+1; scp[i].p=read(); scp[i+1].p=-scp[i].p; m=max(m,scp[i].p); } sort(scp+1,scp+n+1,cmp); for(int i=1;i<=n;i++)insert(rt[i-1],rt[i],1,m,scp[i].p); for(int i=n;i>=1;i--)if(scp[i].pos!=scp[i+1].pos)to[scp[i].pos]=i; for(int i=1;i<=n>>1;i++)if(!to[i])to[i]=to[i-1]; ll pre=1; for(int i=1;i<=q;i++){ int X=read(); ll A=read(); ll B=read(); ll C=read(); ll K=1+(A%C*pre%C+B%C)%C; printf("%lld\n",pre=check(to[X],K)); } return 0; }