题目描述
最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的任务用三元组(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行,每行一个整数,表示查询结果。
输入输出样例
输入样例#1:
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
输出样例#1:
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的一个排列
思路:
可持久化线段树(坑很多很多,诸位小心)
来,上代码:
#include <cstdio> #include <iostream> #include <algorithm> #define maxn 100001 #define LL long long using namespace std; struct T_do { LL time,pi,dis; }; struct T_do do_[maxn<<2]; struct TreeNodeType { LL l,r,dis,sum,bel; TreeNodeType *left,*right; }; struct TreeNodeType *null,*root[maxn<<1]; LL if_z,n,m,num,hash[maxn<<1],size,bef; char Cget; bool if_[maxn<<1]; inline void read_LL(LL &now) { if_z=1,now=0,Cget=getchar(); while(Cget>'9'||Cget<'0') { if(Cget=='-') if_z=-1; Cget=getchar(); } while(Cget>='0'&&Cget<='9') { now=now*10+Cget-'0'; Cget=getchar(); } now*=if_z; } void tree_build(TreeNodeType *&now,LL l,LL r) { now=new TreeNodeType; now->l=l,now->r=r; now->dis=0,now->sum=0; now->bel=0; now->left=null; now->right=null; if(l==r) return ; LL mid=(l+r)>>1; tree_build(now->left,l,mid); tree_build(now->right,mid+1,r); } bool cmp(struct T_do a1,struct T_do a2) { return a1.time<a2.time; } void tree_change(TreeNodeType *&pre,TreeNodeType *&now,LL bel,LL dis,LL sum,LL to) { now=new TreeNodeType; now->sum=pre->sum+sum; now->l=pre->l,now->r=pre->r; now->bel=bel,now->dis=pre->dis+dis; now->left=pre->left,now->right=pre->right; if(now->l==now->r) return ; LL mid=(now->l+now->r)>>1; if(to>mid) tree_change(pre->right,now->right,bel,dis,sum,to); else tree_change(pre->left,now->left,bel,dis,sum,to); } void tree_change_(TreeNodeType *&now,LL bel,LL dis,LL sum,LL to) { if(now->bel!=bel) { TreeNodeType *tmp=new TreeNodeType; tmp->l=now->l,tmp->r=now->r; tmp->dis=now->dis,tmp->bel=bel; tmp->sum=now->sum,tmp->left=now->left; tmp->right=now->right; now=tmp; } now->dis+=dis,now->sum+=sum; if(now->l==now->r) return ; LL mid=(now->l+now->r)>>1; if(to>mid) tree_change_(now->right,bel,dis,sum,to); else tree_change_(now->left,bel,dis,sum,to); } LL tree_query(TreeNodeType *now,LL k) { if(now->l==now->r) return now->sum/now->dis*k; if(k<=now->left->dis) return tree_query(now->left,k); else return tree_query(now->right,k-now->left->dis)+now->left->sum; } int main() { read_LL(m),read_LL(n); LL pi,ai,bi; for(LL i=1;i<=m;i++) { read_LL(ai),read_LL(bi),read_LL(pi); num++,do_[num].dis=1,do_[num].pi=pi,do_[num].time=ai; num++,do_[num].dis=-1,do_[num].pi=-pi,do_[num].time=bi+1; hash[i]=pi; } sort(hash+1,hash+m+1); size=unique(hash+1,hash+m+1)-hash-1; null=new TreeNodeType; null->l=0,null->r=0; null->dis=0,null->sum=0; null->bel=0; null->left=null; null->right=null; tree_build(root[0],1,size); sort(do_+1,do_+num+1,cmp); for(LL i=1;i<=num;i++) { for(LL j=do_[i-1].time+1;j<do_[i].time;j++) { root[j]=root[do_[i-1].time]; } LL pi_; if(do_[i].pi<0) pi_=lower_bound(hash+1,hash+size+1,-do_[i].pi)-hash; else pi_=lower_bound(hash+1,hash+size+1,do_[i].pi)-hash; if(!if_[do_[i].time]) { if_[do_[i].time]=true; tree_change(root[do_[i-1].time],root[do_[i].time],do_[i].time,do_[i].dis,do_[i].pi,pi_); } else { tree_change_(root[do_[i].time],do_[i].time,do_[i].dis,do_[i].pi,pi_); } } LL pre_=1; LL xi,ci; for(LL i=1;i<=n;i++) { read_LL(xi),read_LL(ai),read_LL(bi),read_LL(ci); pre_=1+((ai*pre_+bi)%ci); LL res; if(root[xi]->dis>pre_) res=tree_query(root[xi],pre_); else res=root[xi]->sum; cout<<res; putchar(' '); pre_=res; } return 0; }