BZOJ3932: [CQOI2015]任务查询系统
【传送门:BZOJ3932】
简要题意:
给出n个任务,每个任务给出开始时间和结束时间还有这个任务的优先度
有m个询问,每个询问给出x和k,求第x秒的时候,优先度从小到大k个任务的优先度的和
强制在线
题解:
设c为这个子树有多少个任务,sum为这个子树里的权值和
先把优先度离散化,然后插入主席树里
因为主席树不能够在线区间修改,但是我们可以离线修改然后单点求值,用差分的方式来区间修改,然后将主席树合并得到前缀和
然后单点查询就行了
注意要用long long
参考代码:
#include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<algorithm> using namespace std; typedef long long LL; struct node { int lc,rc;LL c,sum; }tr[5100000];int len,rt[210000]; struct task { int l,r;LL p; }t[210000]; bool cmp(task t1,task t2) { return t1.p<t2.p; } void add(int &u,int l,int r,int p,LL c,LL sum) { if(u==0) u=++len; tr[u].c+=c;tr[u].sum+=sum; if(l==r) return ; int lc=tr[u].lc,rc=tr[u].rc,mid=(l+r)/2; if(p<=mid) add(tr[u].lc,l,mid,p,c,sum); else add(tr[u].rc,mid+1,r,p,c,sum); } void merge(int &u1,int u2) { if(u1==0){u1=u2;return ;} if(u2==0) return ; tr[u1].c+=tr[u2].c;tr[u1].sum+=tr[u2].sum; merge(tr[u1].lc,tr[u2].lc); merge(tr[u1].rc,tr[u2].rc); } LL findans(int u,int l,int r,int p) { if(p>tr[u].c) return tr[u].sum; if(l==r) return LL(p)*tr[u].sum/tr[u].c; int lc=tr[u].lc,rc=tr[u].rc,mid=(l+r)/2; if(p<=tr[lc].c) return findans(lc,l,mid,p); else return findans(rc,mid+1,r,p-tr[lc].c)+tr[lc].sum; } int main() { int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) scanf("%d%d%lld",&t[i].l,&t[i].r,&t[i].p); sort(t+1,t+n+1,cmp); memset(rt,0,sizeof(rt)); int cnt=0; for(int i=1;i<=n;i++) { if(t[i].p!=t[i-1].p) cnt++; add(rt[t[i].l],1,n,cnt,1,t[i].p); add(rt[t[i].r+1],1,n,cnt,-1,-t[i].p); } for(int i=2;i<=n;i++) merge(rt[i],rt[i-1]); LL pre=1; for(int i=1;i<=m;i++) { int x,a,b,c; scanf("%d%d%d%d",&x,&a,&b,&c); int k=1+(a*pre+b)%c; pre=findans(rt[x],1,n,k); printf("%lld\n",pre); } return 0; }
渺渺时空,茫茫人海,与君相遇,幸甚幸甚