BZOJ 3932(CQOI 2015) 题解

题目大意

实现一个查询系统。
每个任务用三元组(Si,Ei,Pi)描述表示任务从第Si秒开始,在第Ei秒后结束(第Si秒和Ei秒任务也在运行),其优先级为Pi。调度系统会经常向查询系统询问,第Xi秒正在运行的任务中,优先级最小的Ki个任务(即将任务按照优先级从小到大排序后取前Ki个)的优先级之和是多少。

我的做法

把p离散化。
按照离散化后的p建立可持久化线段树。
把一个任务拆成两个扔进线段树中。
查询时注意多个任务优先级相同的情况。

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
struct tree
{
    int l,r;
    tree *ls,*rs;
    int num;
    ll sum;
    tree()
    {
        l=r=num=0;
        sum=0;
        ls=rs=0;
    }
};
tree *root[100010];
void mt(tree *&p)
{
    if(p->l==p->r)
     return;
    p->num=p->ls->num+p->rs->num;
    p->sum=p->ls->sum+p->rs->sum;
}
void build(tree *&p,int l,int r)
{
    p=new tree;
    p->l=l;
    p->r=r;
    if(l==r)
     return;
    int mid=(l+r)>>1;
    build(p->ls,l,mid);
    build(p->rs,mid+1,r);
}
void insert(tree *&p1,tree *&p2,int x,int v1,ll v2)
{
    p2=new tree(*p1);
    if(p2->l==p2->r)
    {
        p2->num+=v1;
        p2->sum+=v2;
        return;
    }
    int mid=(p2->l+p2->r)>>1;
    if(x<=mid)
     insert(p1->ls,p2->ls,x,v1,v2);
    else
     insert(p1->rs,p2->rs,x,v1,v2);
    mt(p2);
}
ll query(tree *&p,int k)
{
    if(k==0)
     return 0;
    if(p->l==p->r)
     return p->sum/p->num*k;
    if(k>=p->num)
     return p->sum;
    int mid=(p->l+p->r)>>1;
    int s=p->ls->num;
    if(k<=s)
     return query(p->ls,k);
    return p->ls->sum+query(p->rs,k-s);
}
struct p
{
    int a,b,c;
    ll d;
    p(int a_=0,int b_=0,int c_=0,ll d_=0)
    {
        a=a_;
        b=b_;
        c=c_;
        d=d_;
    }
};
bool cmp(p a,p b)
{
    return a.a<b.a;
}
p a[200010];
int d[100010];
int x[100010];
int y[100010];
int z[100010];
int main()
{
    freopen("bzoj3932.in","r",stdin);
    freopen("bzoj3932.out","w",stdout);
    int n,m;
    scanf("%d%d",&m,&n);
    int i;
    for(i=1;i<=m;i++)
    {
        scanf("%d%d%d",&x[i],&y[i],&z[i]);
        d[i]=z[i];
    }
    sort(d+1,d+m+1);
    int tot=unique(d+1,d+m+1)-d-1;
    for(i=1;i<=m;i++)
    {
        int t=lower_bound(d+1,d+tot+1,z[i])-d;
        a[2*i-1]=p(x[i],t,1,z[i]);
        a[2*i]=p(y[i]+1,t,-1,-z[i]);
    }
    build(root[0],1,tot);
    sort(a+1,a+2*m+1,cmp);
    for(i=1;i<=2*m;i++)
    {
        if(a[i].a>n)
         break;
        tree *now;
        insert(root[a[i-1].a],now,a[i].b,a[i].c,a[i].d);
        root[a[i].a]=now;
    }
    for(i=1;i<=n;i++)
     if(!root[i])
      root[i]=root[i-1];
    ll pre=1;
    for(i=1;i<=n;i++)
    {
        int X,A,B,C,K;
//      scanf("%d%d%d%d",&X,&A,&B,&C);
//      K=1+(A*pre+B)%C;
        scanf("%d%d",&X,&K);
        pre=query(root[X],K);
        printf("%lld\n",pre);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值