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;
}

 

posted @ 2018-04-08 19:55  Star_Feel  阅读(204)  评论(0编辑  收藏  举报