BZOJ3932: [CQOI2015]任务查询系统(洛谷P3168)

292 篇文章 1 订阅
281 篇文章 1 订阅

主席树 差分

BZOJ题目传送门
洛谷题目传送门

先利用差分,一个数出现在 [s,e] 等价于在 s 时刻把这个数的出现次数+1,在t+1时刻-1。
那么我们可以用主席树维护。记录sum表示子树大小,x表示子树优先级和,把优先级离散后就可以维护了。

注意细节。

代码:

#include<cctype>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 100005
using namespace std;
typedef long long LL;
struct dt{ int t,p,x; }a[N*2];
struct tree{ int ls,rs,sum; LL x; }t[N*50];
int n,m,nd,num,rt[N],b[N];
LL pre=1;
inline char readc(){
    static char buf[100000],*l=buf,*r=buf;
    if (l==r) r=(l=buf)+fread(buf,1,100000,stdin);
    if (l==r) return EOF; return *l++;
}
inline int _read(){
    int x=0; char ch=readc();
    while (!isdigit(ch)) ch=readc();
    while (isdigit(ch)) x=x*10+ch-48,ch=readc();
    return x;
}
bool cmp(dt x,dt y){ return x.t<y.t; }
void ntlz(int &x,int l,int r){
    t[x=++nd].sum=t[x].x=0;
    if (l==r) return; int mid=l+r>>1;
    ntlz(t[x].ls,l,mid),ntlz(t[x].rs,mid+1,r);
}
void build(int &x,int l,int r,int fa,int p,int w){
    t[x=++nd].ls=t[fa].ls,t[x].rs=t[fa].rs;
    t[x].sum=t[fa].sum+w,t[x].x=t[fa].x+(LL)w*b[p];
    if (l==r) return; int mid=l+r>>1;
    if (p<=mid) build(t[x].ls,l,mid,t[fa].ls,p,w);
    else build(t[x].rs,mid+1,r,t[fa].rs,p,w);
}
LL srch(int x,int l,int r,LL k){
    if (k>=t[x].sum) return t[x].x;
    if (l==r) return t[x].x/t[x].sum*k;
    int ls=t[x].ls,df=t[ls].sum,mid=l+r>>1;
    if (df>=k) return srch(ls,l,mid,k);
    else return t[ls].x+srch(t[x].rs,mid+1,r,k-df);//记得加上左子树的权值
}
int main(){
    n=_read(),m=_read();
    for (int i=1;i<=n;i++){
        int s=_read(),t=_read(),p=b[i]=_read();
        a[i*2-1]=(dt){s,p,1}; a[i*2]=(dt){t+1,p,-1};
    }
    sort(b+1,b+n+1),sort(a+1,a+n*2+1,cmp);
    num=unique(b+1,b+n+1)-(b+1),ntlz(rt[0],1,num);
    for (int i=1;i<=n*2;i++){
        int t=a[i].t,x=a[i].x;
        int p=lower_bound(b+1,b+num+1,a[i].p)-b;
        for (int j=a[i-1].t+1;j<t;j++) rt[j]=rt[j-1];
        //当这个时刻没有任务开始时要把之前那个时刻的给copy过来
        if (a[i].t!=a[i-1].t) build(rt[t],1,num,rt[t-1],p,x);
        //如果两个任务发生在同一时刻的话直接用同一个根
        else build(rt[t],1,num,rt[t],p,x);
    }
    while (m--){
        LL x=_read(),A=_read(),B=_read(),C=_read();
        C=1+(A*pre+B)%C,pre=srch(rt[x],1,num,C);
        printf("%lld\n",pre);
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值