3932: [CQOI2015]任务查询系统
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4113 Solved: 1334
[Submit][Status][Discuss]
Description
最近实验室正在为其管理的超级计算机编制一套任务管理系统,而你被安排完成其中的查询部分。超级计算机中的
任务用三元组(Si,Ei,Pi)描述,(Si,Ei,Pi)表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行
),其优先级为Pi。同一时间可能有多个任务同时执行,它们的优先级可能相同,也可能不同。调度系统会经常向
查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个
)的优先级之和是多少。特别的,如果Ki大于第Xi秒正在运行的任务总数,则直接回答第Xi秒正在运行的任务优先
级之和。上述所有参数均为整数,时间的范围在1到n之间(包含1和n)。
Input
输入文件第一行包含两个空格分开的正整数m和n,分别表示任务总数和时间范围。接下来m行,每行包含三个空格
分开的正整数Si、Ei和Pi(Si≤Ei),描述一个任务。接下来n行,每行包含四个空格分开的整数Xi、Ai、Bi和Ci,
描述一次查询。查询的参数Ki需要由公式 Ki=1+(Ai*Pre+Bi) mod Ci计算得到。其中Pre表示上一次查询的结果,
对于第一次查询,Pre=1。
Output
输出共n行,每行一个整数,表示查询结果。
Sample Input
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 6
2 3 3
1 3 2
3 3 4
3 1 3 2
1 1 3 4
2 2 4 3
Sample Output
2
8
11
8
11
HINT
样例解释
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的一个排列
分析:主席树的第一题......发现自己理解地不是很深.
若对于每一个时间建主席树的话,第i棵可以用来维护时间为1~i的优先级在[x,y]的任务个数和优先级之和.对于每一个时间点都建主席树则会有点浪费,因为每次更改操作只会设计到2个时间点.考虑用操作来建主席树.第i棵可以维护第1~i次操作后优先级在[x,y]的任务个数和优先级之和.那么每一次操作只需要在初始时间和结束时间+1处更改就行了(类似于差分).对操作的时间排序,接着求出每个时间点最后被影响的操作序号.最后查询就好了.
搞清楚主席树表示的意义很重要!碰到第k小/大这种字眼也要很快反应过来该用什么方法,还要知道利用主席树要维护什么东西!与权值线段树联系起来思考.
#include <cstdio> #include <cstring> #include <iostream> #include <algorithm> using namespace std; const int maxn = 200010; typedef long long ll; ll ans; int n,m,tot,cur[maxn],cnt,root[maxn],mx; struct node { int left,right,sizee; ll sum; }e[maxn * 25]; struct node2 { int pos,val; }a[maxn]; bool cmp(node2 a,node2 b) { return a.pos < b.pos; } void update(int l,int r,int x,int &y,int v) { e[y = ++cnt] = e[x]; e[y].sizee += (v > 0 ? 1 : -1); e[y].sum += v; if (l == r) return; int mid = (l + r) >> 1; if (abs(v) <= mid) update(l,mid,e[x].left,e[y].left,v); else update(mid + 1,r,e[x].right,e[y].right,v); } ll query(int l,int r,int x,int k) { if (e[x].sizee <= k) return e[x].sum; if (l == r) return 1LL * l * k; int mid = (l + r) >> 1; if (k <= e[e[x].left].sizee) return query(l,mid,e[x].left,k); else return e[e[x].left].sum + query(mid + 1,r,e[x].right,k - e[e[x].left].sizee); } int main() { scanf("%d%d",&n,&m); for(int i = 1; i <= n; i++) { int x,y,z; scanf("%d%d%d",&x,&y,&z); a[++tot].pos = x; a[tot].val = z; a[++tot].pos = y + 1; a[tot].val = -z; mx = max(mx,z); } sort(a + 1,a + 1 + tot,cmp); for (int i = 1; i <= tot; i++) update(1,mx,root[i - 1],root[i],a[i].val); for (int i = tot; i >= 1; i--) //维护每一个被更改的时间点最后在哪里被更改的 if (a[i].pos != a[i + 1].pos) cur[a[i].pos] = root[i]; for (int i = 1; i <= m; i++) //如果当前时间点没有被更改,那么就和前一个时间点的情况一样 if (!cur[i]) cur[i] = cur[i - 1]; ans = 1; for (int i = 1; i <= m; i++) { ll t,x,y,z,k; scanf("%lld%lld%lld%lld",&t,&x,&y,&z); k = (1LL * x * ans + y) % z + 1; ans = query(1,mx,cur[t],k); printf("%lld ",ans); } return 0; }