[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行,每行一个整数,表示查询结果。
输入输出样例
输入样例#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的一个排列
简述一下题意:给出一个区间(长度最长为\(10^6\)),以及m次区间修改和区间的大小n.然后是n次询问,求出包含x位置的所有区间中的前k个的和.强制在线.
因为序列的长度并不长,所以我们可以考虑用一些数据结构来记录下覆盖点下标为pos的所有区间.然后还要求前k小的和,这里可以用主席树来维护.
下面直接讲一下做法吧:主席树+差分
- 将每个任务看作是在区间[l,r]上加一个值(区间修改).
- 将一个区间[l,r]的修改为在下标为l的位置+1,在r+1的位置-1.
- 将所有修改的位置按照位置顺序排序,每个下标都储存一些区间修改的值.
- 在修改主席树和的时候直接加上一次修改的值乘以它的符号(前面记录的加或减),这样就统计出了每个位置的和.
- 统计时直接按照主席树的查询方式查询.
因为一个下标的位置上有可能有多次修改,所以要一起记录到同一个下标位置上,但是又只需要记录n个版本的主席树,所以可以用一个数组辅助一下.
下面贴一下代码
#include<bits/stdc++.h>
using namespace std;
const int N=100000+5;
typedef long long lol;
int n, m, cnt = 0, cntm = 0, size;
int w[N*2], rk[N*2];
int root[N], c[N*2];
struct task{
int pos, f, val;
}mi[N*3];
struct president_tree{
int ls, rs, sz;
lol sum;
}t[N*40];//数组开大点
int gi(){
int ans = 0 , f = 1; char i = getchar();
while(i<'0'||i>'9'){if(i=='-')f=-1;i=getchar();}
while(i>='0'&&i<='9'){ans=ans*10+i-'0';i=getchar();}
return ans * f;
}
bool cmp(task a,task b){
return a.pos < b.pos;
}
void updata(int &node,int last,int f,int pos,int l=1,int r=m){
node = ++cnt; t[node] = t[last];
t[node].sum += (lol) f*w[pos]; t[node].sz += f;
if(l == r) return; int mid = (l+r>>1);
if(pos <= mid) updata(t[node].ls , t[last].ls , f , pos , l , mid);
else updata(t[node].rs , t[last].rs , f , pos , mid+1 , r);
}
lol query(int node,int k,int l=1,int r=m){
if(l == r) return t[node].sum/t[node].sz*(lol)k;
int mid = (l+r>>1), s = t[t[node].ls].sz;
if(k <= s) return query(t[node].ls,k,l,mid);
else return t[t[node].ls].sum + query(t[node].rs,k-s,mid+1,r);
}
int main(){
//freopen("data.in","r",stdin);
int x, y, z, pos; n = gi(); m = gi();
for(int i=1;i<=n;i++){
x = gi(); y = gi(); z = gi();
mi[++cntm].pos = x; mi[cntm].f = 1; mi[cntm].val = z;
mi[++cntm].pos = y+1; mi[cntm].f = -1; mi[cntm].val = z;//记录每个位置上的修改
w[i] = z;
}
sort(w+1 , w+n+1); sort(mi+1 , mi+cntm+1 , cmp);
for(int i=1;i<=cntm;i++)
rk[i] = lower_bound(w+1,w+n+1,mi[i].val)-w;
c[0] = 0;
for(int i=1, j=1;i<=m;i++){
while(j<=cntm && mi[j].pos == i)
updata(c[j] , c[j-1] , mi[j].f , rk[j]) , j++;//将同一位置上的修改加到同一个下标
root[i] = c[j-1];
}
lol lans = 1, kth;
for(int i=1;i<=m;i++){
pos = gi(); x = gi(); y = gi(); z = gi();
kth = (x*lans+y) % z + 1;
if(t[root[pos]].sz <= kth) lans = t[root[pos]].sum;
else lans = (lol) query(root[pos],kth);
//printf("kth=%lld size=%d\n",kth,t[root[pos]].sz);
printf("%lld\n",lans);
}
return 0;
}