P3168 [CQOI2015]任务查询系统
题目描述
最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的任务用三元组(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行,每行一个整数,表示查询结果。
输入输出样例
4 3
1 2 6
2 3 3
1 3 2
3 3 4
3 1 3 2
1 1 3 4
2 2 4 3
2
8
11
说明
样例解释
K1 = (1*1+3)%2+1 = 1
K2 = (1*2+3)%4+1 = 2
K3 = (2*8+4)%3+1 = 3
对于100%的数据,1<=m,n,Si,Ei,Ci<=100000,0<=Ai,Bi<=100000,1<=Pi<=10000000,Xi为1到n的一个排列
Solution:
本题主席树板子。
题意是个区间修改单点查询,只不过查询的时候是要前k小的和。
每个区间$[l,r]+k$,而查询只要一个位置$x_i$的情况,想到差分序列,然后搞前缀和做到单点修改单点查询。
我们对等级$P_i$离散,并构建主席树,由于要求前$k$小的等级和,所以多维护一个等级和的前缀和$sum$。
对于每个询问,沿着查询的时刻的权值线段树自顶向下判断,类比求第$k$小数,每次累加返回$sum$就好了。(注意,这样查询会出现一个问题,当一个等级在同一时刻多次出现时,就会出现遍历到该等级子节点时$siz>k$,此时不能直接返回$sum$,而应返回$sum/siz*k$)
代码:
/*Code by 520 -- 9.13*/ #include<bits/stdc++.h> #define il inline #define ll long long #define RE register #define For(i,a,b) for(RE int (i)=(a);(i)<=(b);(i)++) #define Bor(i,a,b) for(RE int (i)=(b);(i)>=(a);(i)--) using namespace std; const int N=200005; int n,m,rt[N],*Q[N],w[N],tot,cnt,num; struct arr{ int pos,val,tag; bool operator<(const arr &a)const{return pos<a.pos;} }a[N<<1]; struct node{ int ls,rs,siz; ll sum; }t[N*40]; int gi(){ int a=0;char x=getchar(); while(x<'0'||x>'9')x=getchar(); while(x>='0'&&x<='9')a=(a<<3)+(a<<1)+(x^48),x=getchar(); return a; } il bool cmp(const int *a,const int *b){return *a<*b;} void build(int l,int r,int &rt){ t[rt=++tot].siz=0,t[rt].sum=0; if(l==r) return; int m=l+r>>1; build(l,m,t[rt].ls),build(m+1,r,t[rt].rs); } void update(int k,int tag,int l,int r,int lst,int &rt){ rt=++tot; t[rt]=t[lst],t[rt].siz+=tag,t[rt].sum+=tag*w[k]; if(l==r) return; int m=l+r>>1; if(k<=m) update(k,tag,l,m,t[lst].ls,t[rt].ls); else update(k,tag,m+1,r,t[lst].rs,t[rt].rs); } ll query(int rt,int k,int l,int r){ if(k>=t[rt].siz) return t[rt].sum; if(l==r) return t[rt].sum/t[rt].siz*k; int siz=t[t[rt].ls].siz,m=l+r>>1; if(k<=siz) return query(t[rt].ls,k,l,m); else return t[t[rt].ls].sum+query(t[rt].rs,k-siz,m+1,r); } int main(){ n=gi(),m=gi(); int x,y,z; For(i,1,n) { x=gi(),y=gi(),z=gi(); a[i]=arr{x,z,1},a[i+n]=arr{y+1,z,-1}; Q[i]=&a[i].val,Q[i+n]=&a[i+n].val; } sort(Q+1,Q+n*2+1,cmp); int lst=-1; For(i,1,n<<1) if(*Q[i]!=lst) lst=*Q[i],*Q[i]=++cnt,w[cnt]=lst; else *Q[i]=cnt; sort(a+1,a+n*2+1); build(1,cnt,rt[0]); lst=rt[0]; for(RE int i=1,j=1;i<=m;i++) { rt[i]=lst; for(;a[j].pos==i&&j<=(n<<1);j++) update(a[j].val,a[j].tag,1,cnt,lst,rt[i]),lst=rt[i]; } ll pre=1,k,a,b,c; while(m--){ x=gi(),a=gi(),b=gi(),c=gi(); k=(a*pre%c+b)%c+1; printf("%lld\n",(pre=query(rt[x],k,1,cnt))); } return 0; }