bzoj3932

首先将i这个任务的重要度的正值用前向星挂在l上,负值挂在r+1上(差分)

对每个任务的重要度离散之后建一棵线段树,然后以时间为轴建一棵主席树

细节贼多(因为某个<=打成==调了2小时)

感谢zzy大佬,gyz大佬的帮忙查错orz

/**************************************************************

    Problem: 3932

    User: syh0313

    Language: C++

    Result: Accepted

    Time:7308 ms

    Memory:136720 kb

****************************************************************/

 

#include <iostream>

#include <cstdio>

#include <cstdlib>

#include <cmath>

#include <algorithm>

#include <cstring>

#include <string>

#include <map>

#define lch a[n].lc

#define rch a[n].rc

using namespace std;

const int maxn=1e5+10;

int n,m,ll[maxn],rr[maxn],cnt,lim,root[maxn],topt,lala;

long long b[maxn],pp[maxn],pre=1;

int w[maxn<<2],to[maxn<<2],nt[maxn<<2],st[maxn<<2],tot;

struct da{int lc,rc;long long sum,si;}a[maxn*50];

map<int,int>f,line,ff;

void add(int x,int y,int z)

{to[++tot]=y; nt[tot]=st[x]; st[x]=tot; w[tot]=z;}

void updata(int n)

{

    a[n].si=a[lch].si+a[rch].si;

    a[n].sum=a[lch].sum+a[rch].sum;

}

void build_tree(int &n,int l,int r)

{

    n=++topt; if (l==r) return;

    int mid=(l+r)>>1;

    build_tree(lch,l,mid); build_tree(rch,mid+1,r);

}

void tree_add(int old,int &n,int l,int r,int lc,long long k)

{

    if (n<lim) n=++topt;

    if (l==r && r==lc)

    {

        if (ff[lc]<=lala)

        {

          ff[lc]=lala+1;

          a[n].si=a[old].si+k;

          a[n].sum=a[old].sum+1ll*k*b[lc];

        }

        else {a[n].si+=k; a[n].sum+=1ll*k*b[lc];}

        return;

    }

    int mid=(l+r)>>1;

    if (lc<=mid) {if (!rch) rch=a[old].rc; tree_add(a[old].lc,lch,l,mid,lc,k);}

    else {if (!lch) lch=a[old].lc; tree_add(a[old].rc,rch,mid+1,r,lc,k);}

    updata(n);

}

long long qury(int n,int l,int r,int k)

{

    if (l==r) return 1ll*k*b[l];

    if (!k) return 0;

    int mid=(l+r)>>1;

    if (a[lch].si>=k) return qury(lch,l,mid,k);

     else return a[lch].sum+qury(rch,mid+1,r,k-a[lch].si);

}

int main()

{

    //freopen("1.in","r",stdin);

    //freopen("my.out","w",stdout);

    scanf("%d%d",&n,&m);

    for (int i=1;i<=n;i++)

    {

        scanf("%d%d%lld",&ll[i],&rr[i],&pp[i]);

        if (!f[pp[i]]) {f[pp[i]]=1; b[++cnt]=pp[i];}

    }

    sort(b+1,b+cnt+1);

    for (int i=1;i<=cnt;i++) line[b[i]]=i;

    for (int i=1;i<=n;i++) add(ll[i],line[pp[i]],1),add(rr[i]+1,line[pp[i]],-1);

    build_tree(root[0],1,cnt);

    for (int i=1;i<=m;i++)

    {

        int p=st[i];

        if (!p)

        {

            root[i]=++topt;

            a[root[i]].lc=a[root[i-1]].lc;

            a[root[i]].rc=a[root[i-1]].rc;

            a[root[i]].si=a[root[i-1]].si;

            a[root[i]].sum=a[root[i-1]].sum;

        }

        lim=topt+1;

        while (p)

        {

            tree_add(root[i-1],root[i],1,cnt,to[p],w[p]);

            p=nt[p];

        }

        lala++;

    }

    for (int i=1;i<=m;i++)

    {

        int xx; long long aa,bb,cc,kk;

        scanf("%d%lld%lld%lld",&xx,&aa,&bb,&cc);

        kk=1+(aa*pre+bb)%cc;

        if (kk>=a[root[xx]].si) pre=a[root[xx]].sum;

         else pre=qury(root[xx],1,cnt,kk);

        printf("%lld\n",pre);

    }

return 0;

}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值