BZOJ3932: [CQOI2015]任务查询系统 主席树
3932: [CQOI2015]任务查询系统
Time Limit: 20 Sec Memory Limit: 512 MBSubmit: 4869 Solved: 1652
[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的一个排列
Source
题解:这是一个主席树的题目,首先需要读清楚题目,有n个任务,所以可以通过离散化使得变成n个优先级,因为一个任务是在一段区间中出现的,所以很显然我们可以用到差分思想,在st++,end+1处--。作为一种高级的前缀和,很容易想到我们要以时间顺序依次建立每颗权值线段树,线段树维护的是某一时刻某一个优先级出现的次数。这里要注意的是时间不一定连续,所以在同一时间的就以当前时间的root开始建树,否则沿用前一时刻的,写成代码可以对于每一个i都将root[i]=root[i-1]就行。 PS:在试着少看题解,不然比赛时仍旧不会做,想的时候想到了差分,离散化,按照时间建树,以及主席树维护的肯定是优先级的出现次数,但是还是不太清楚怎么写。
#include<bits/stdc++.h> #define ll long long #define pb push_back #define _mp make_pair #define ldb long double using namespace std; const int maxn=2e5+100; inline ll read() { ll x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } struct node { ll l,r; ll sum,v; }no[maxn*40]; struct sr { int x,num,tp,val; }sf[maxn*2]; int id[maxn],nid[maxn],pri[maxn]; ll root[maxn<<1]; int cnt=0,tot=0,n,m; bool cmp1( int a, int b){ return pri[a]<pri[b]; } bool cmp2(const sr& a,const sr& b) { return a.x<b.x; } void insert(ll& now,int l,int r,int pl,int val,int type) { no[++cnt]=no[now]; now=cnt; no[now].v+=type; no[now].sum+= val; if(l==r)return; int mid=(l+r)>>1; if(pl<=mid)insert(no[now].l,l,mid,pl,val,type); else if(pl>mid)insert(no[now].r,mid+1,r,pl,val,type); } ll query(ll x,int l,int r,ll k) { if(l==r) { return no[x].sum; } int mid=(l+r)>>1; ll tmp=0; ll ss=no[no[x].l].v; if(ss>=k) { tmp+=query(no[x].l,l,mid,k); } else { tmp+=no[no[x].l].sum; tmp+=query(no[x].r,mid+1,r,k-ss); } return tmp; } int pp,qq,rr,ss; int main() { n=read();m=read(); for(int i=1;i<=n;i++) { pp=read();qq=read();rr=read(); pri[i]=rr;id[i]=i; sf[++tot].x=pp;sf[tot].val=rr;sf[tot].tp=1; sf[++tot].x=qq+1;sf[tot].val=-rr;sf[tot].tp=-1; } sort(id+1,id+1+n,cmp1); for(int i=1;i<=n;i++)nid[id[i]] =i; // for(int i=1;i<=n;i++)cout<<nid[i]<<endl; for(int i=1;i<=tot;i+=2) { sf[i].num=sf[i+1].num=nid[(i+1)/2]; } sort(sf+1,sf+1+tot,cmp2); int j=1; for(int i=1;i<=m;i++) { root[i]=root[i-1]; while(sf[j].x==i) { insert(root[i],1,n,sf[j].num,sf[j].val,sf[j].tp); j++; } } //cout<<cnt<<endl; ll pre=1; for(int i=1;i<=m;i++) { ss=read();pp=read();qq=read();rr=read(); ll tmp=1+(pp*pre+qq)%rr; //cout<<tmp<<endl; pre=query(root[ss],1,n,tmp); printf("%lld\n",pre); } }