[CQOI2015]任务查询系统
首先根据题目要求,我们需要求在第Xi秒时优先级最小的Ki个任务的优先级之和,而这个Ki与之前的答案有关,所以这道题是强行在线的。我也没想过离线怎么做。
离散化优先级,假如我们为每一秒建一棵线段树,存储各个优先级的信息,就可以直接查找了,但是时空都会爆炸。所以问题在于如何建立秒与秒之间的关系,以减少时空开销。
1:假如没有任何任务,那么第 i 秒的情况与第一秒相同。到一般情况,对于任何一段没有新任务的时间段,这些时间所涵盖的信息是相同的。也就是说之后的信息是建立在之前信息之上的,第 i 秒的信息是建立在第 i-1 秒之上的。
2:考虑一个任务(Si,Ei,Pi),这一个任务带来的影响在时间段 [ Si , Ei ] 内是相同的,我们就想到差分了,只需要在第 Si 秒将贡献加上,在第 Ei + 1 秒将贡献移除就可以了。
3:实现采用主席树。
// q.c #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> #include<vector> using namespace std; typedef long long LL; const int M=100000+10; struct Node { int l,r,lc,rc,size; LL sum; Node():l(0),r(0),lc(0),rc(0),size(0),sum(0) {} }; int f[M]; struct SegmentTree { int cnt; Node nd[18*M<<2]; SegmentTree():cnt(0) {} void update(int o) { Node &p=nd[o],&lc=nd[nd[o].lc],&rc=nd[nd[o].rc]; p.size=lc.size+rc.size; p.sum=lc.sum+rc.sum; } void build(int &o,int l,int r) { if(!o) o=++cnt; Node &p=nd[o]; p.l=l,p.r=r; if(l!=r) { int mid=(l+r)>>1; build(p.lc,l,mid); build(p.rc,mid+1,r); } } void insert(int &o,int po,int x,int k) { if(!o) o=++cnt; Node &p=nd[o]; p=nd[po]; if(p.l==p.r) p.size+=k,p.sum+=(LL)k*f[x]; else { int mid=(p.l+p.r)>>1; if(x<=mid) p.lc=0,insert(p.lc,nd[po].lc,x,k); else p.rc=0,insert(p.rc,nd[po].rc,x,k); update(o); } } LL query(int o,int k) { Node p=nd[o]; if(p.l==p.r) return p.sum/p.size*k; else if(k<=nd[p.lc].size) return query(p.lc,k); else return nd[p.lc].sum+query(p.rc,k-nd[p.lc].size); } }t; struct Ques { int id,tag; }; vector<Ques> qs[M]; struct Data { int x,y; bool operator < (const Data &A) const { if(x!=A.x) return x<A.x; return y<A.y; } }w[M]; int m,n,v[M],root[M],cnt; int main() { freopen("cqoi15_query.in","r",stdin); freopen("cqoi15_query.out","w",stdout); scanf("%d%d",&m,&n); int a,b,c; for(int i=1;i<=m;i++) { scanf("%d%d%d",&a,&b,&c); w[i].x=c,w[i].y=i; qs[a].push_back((Ques){i,1}); qs[b+1].push_back((Ques){i,-1}); } sort(w+1,w+m+1); for(int i=1;i<=m;i++) { if(w[i].x!=w[i-1].x) v[w[i].y]=++cnt,f[cnt]=w[i].x; else v[w[i].y]=cnt; } t.build(root[0],1,cnt); for(int i=1;i<=n;i++) { int sz=qs[i].size(); root[i]=root[i-1]; int x=0; for(int j=0;j<sz;j++) { t.insert(x,root[i],v[qs[i][j].id],qs[i][j].tag); root[i]=x; x=0; } } int x,k; LL pre=1; for(int i=1;i<=n;i++) { scanf("%d%d%d%d",&x,&a,&b,&c); k=(int)((a*pre+b)%c)+1; if(k>=t.nd[root[x]].size) pre=t.nd[root[x]].sum; else pre=t.query(root[x],k); printf("%lld\n",pre); } return 0; }
需要注意的是对于同一秒有多个任务开始或结束的情况,这其实牵扯到自己对主席树的理解以及写法,我也不会表达,我采用了一个迭代实现。
相关推荐
tulensa 2020-07-19
junzi 2020-06-11
RememberMePlease 2020-06-03
shengge0 2020-06-01
kjh00abc 2020-05-31
sdaq 2020-05-30
gaitiangai 2020-05-26
tianzyc 2020-05-18
zhangjunguo00 2020-04-23
huacuilaifa 2020-04-26
happinessaflower 2020-04-26
coulder 2020-04-21
wannagonna 2020-04-16
wishchinYang 2020-04-08
teresalxm 2020-02-18