P3168 任务查询系统

本文介绍了一种高效的数据结构——主席树,用于处理区间修改和单点查询问题。通过在时间点上构建树,使得每个时间点对应一棵树,表示当前时刻的任务优先级情况。文章详细解释了如何通过排序、建树和查询操作来实现这一过程。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

区间修改+单点查询

利用时间点建树,因为主席树建树时第i结点会继承第i-1个结点的信息,可以只修改区间端点使每个时间点对应的树恰好表示该时间的任务优先级情况。

1.把区间端点全部放入数组task中排序,起始点时间不变,结束点时间加一。

2.按时间从1到n建树,每次建树把task中所有时间为i的结点建到树里,起始点加入树(标记为1),结束点在树中减去(标为-1)

3.直接查询时间点对应的那棵树即可

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
typedef long long ll;
int n,dis[100010],cnt=1,rt[100010];
struct Task
{
    int s,p,h;
    bool operator <(const Task &jkl)const
    {
        return s<jkl.s;
    }
}task[200010];
struct node
{
    int l,r,t;
    ll sum,v;
}tree[100010*40];
void add(int l,int r,int &rt,int q,int k,ll p,ll h,int t)
{
    if(tree[rt].t!=t)
    {
        rt=cnt++;
        tree[rt]=tree[q];
        tree[rt].t=t;
    }
    if(l==r)
    {
        tree[rt].v+=h;
        tree[rt].sum+=h*p;
        return;
    }
    int mid=(l+r)>>1;
    if(k<=mid)
        add(l,mid,tree[rt].l,tree[q].l,k,p,h,t);
    else
        add(mid+1,r,tree[rt].r,tree[q].r,k,p,h,t);
    tree[rt].v=tree[tree[rt].l].v+tree[tree[rt].r].v;
    tree[rt].sum=tree[tree[rt].l].sum+tree[tree[rt].r].sum;
}
ll query(int l,int r,int q,int k)
{
    if(l==r)
    {
        if(!tree[q].sum)
            return 0;
        else
        return tree[q].sum/tree[q].v*k;
    }
    int sum=tree[tree[q].l].v,mid=(l+r)>>1;
    if(k<=sum)
        return query(l,mid,tree[q].l,k);
    else
        return tree[tree[q].l].sum+query(mid+1,r,tree[q].r,k-sum);
}
int main()
{
    //freopen("1.txt","r",stdin);
    int m,con=1;
    ll ans=1;
    scanf("%d%d",&m,&n);
    for(int i=1;i<=m;++i)
    {
        scanf("%d%d%d",&task[con].s,&task[con+1].s,&task[con].p);
        dis[i]=task[con].p;
        task[con++].h=1;
        task[con].p=task[con-1].p;
        ++task[con].s;
        task[con++].h=-1;
    }
    sort(dis+1,dis+m+1);
    sort(task+1,task+con);
    int ed=unique(dis+1,dis+m+1)-dis-1;
    task[con].s=-1;
    int id=1;
    for(int i=1;i<=n;++i)
    {
        int f=0;
        while(task[id].s==i)
        {
            int mid=lower_bound(dis+1,dis+ed+1,task[id].p)-dis;
            f=1;
            add(1,ed,rt[i],rt[i-1],mid,task[id].p,task[id].h,i);
            ++id;
        }
        if(!f)
        rt[i]=rt[i-1];
    }
    while(n--)
    {
        int x;
        ll k,a,b,c;
        scanf("%d%lld%lld%lld",&x,&a,&b,&c);
        k=1+(a*ans+b)%c;
        ans=query(1,ed,rt[x],k);
        printf("%lld\n",ans);
    }
    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值