日程管理

日程管理

时间限制: 2 Sec 内存限制: 512 MB

题目描述
幽吞是幻想乡中一个非常有地位的人。她日理万机,事务繁多,感到自己已经快理不过来了。于是她决定开发一个日程管理软件来帮组自己管理任务。
对于每个任务i有一个对应的截止日期ti以及收益pi,表示若幽香能在不晚于第ti天完成这个任务,使可以得到pi的收益。幽香办事的能力非常强,任何任务部可以用恰好一天时间做完。但由于任务实在太多了,有时候并不能完成所有任务,于是幽香会想要知道这个情况下,完成任务可以给她带来最大的累积收益是多少。
由于幻想乡的人们十分善变,任务总是不断发生肴变化。幽香希望这个管理软件还能够支持插入一个任务,和删除一个任务的操作。
具体的说.幽香希t}支持以下7个操作:
1. ADD t p:表示新添一个截止日期为t,收益为p的任务。
2. DEL t p:表示删除一个截止日期为t,收益为p的任务。如果有多个这
样的任务,只删除一个。数据保证这样的任务一定存在。
在每次操作执行完毕后,你都甲需要输出能够完成的任务的最大收益和。
幽香一共有T天需要安排,从第1天到第T天,你能帮助她写出这个高效率的软件吗?

输入
第一行有两个正整数T和Q,表示天数和操作的个数。
接下来Q行,其中第i行表示第i个操作,形式为ADD t p或DEL t p,其具体意义如体面所述。

输出
要求对于每一次操作,输出一个整数在执行完该后幽香能获得的最大收益和。

样例输入
5 10
ADD 1 5811
ADD 3 5032
DEL 3 5032
ADD 3 5550
ADD 5 3486
DEL 1 5811
DEL 3 5550
ADD 4 5116
ADD 3 9563
ADD 5 94

样例输出
5811
10843
5811
11361
14847
9036
3486
8602
18165
18259

数据范围
T<=300000,Q<=300000

来源
ctsc2015 day2

题解

幽香。。陈老师的题。。
假设只有一组询问,考虑贪心,将任务按照p排序,从大到小插入即可。
所以我们可以拿2棵线段树分别维护已经插入的和暂时未插入的任务。
为了方便操作,再写一棵线段树表示每个时间点能否再增加任务。
对于每次ADD操作,先在插入的t后面寻找一个最左边的不能增加任务的位置。如果找不到则显然直接加入这个任务。若找到了,则在【1,这个位置】这段区间内寻找最小值,并和这次操作的t比较即可。
对于每次DEL操作,如果没有插入,则直接删除即可。
考虑已经插入的情况,则显然应该寻找最后一个不能增加任务的位置,并选择t在这个位置之后的节点中p最小的来替代。
以上题解来自本蒟蒻口胡。
要看正常的题解的话去找cls的ppt。

代码

#include<iostream> 
#include<cstdio> 
#include<cstdlib> 
#include<cstring> 
#include<string> 
#include<cmath> 
#include<set>
#include<algorithm> 
#define inf 1050000000
#define N 300005
using namespace std;
int n,Q,ans;
struct node{int minn,pos;};
struct info{int minn,tag;};

class seg_tree_2
{
  node merge(node a,node b)
  {
    if(a.minn<b.minn)return a;
    return b;
  }
  public:
  node t[N*4];multiset<int>q[N];
  void build(int x,int l,int r)
  {
    if(l==r)
    {
      t[x].minn=inf;t[x].pos=l;
      q[l].insert(inf);return;
    }
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    build(lc,l,mid);build(rc,mid+1,r);
    t[x]=merge(t[lc],t[rc]);
  }
  void insert(int x,int l,int r,int ti,int p)
  {
    if(l==r)
    {
      t[x].minn=min(t[x].minn,p);
      q[l].insert(p);return;
    }
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    if(ti<=mid)insert(lc,l,mid,ti,p);
    else insert(rc,mid+1,r,ti,p);
    t[x]=merge(t[lc],t[rc]);    
  }
  bool erase(int x,int l,int r,int ti,int p)
  {
    if(t[x].minn>p)return false;
    if(l==r)
    {
      q[l].erase(q[l].find(p));
      t[x].minn=*q[l].begin();
      return true;
    }
    int mid=l+r>>1,lc=x<<1,rc=lc+1,res;
    if(ti<=mid)res=erase(lc,l,mid,ti,p);
    else res=erase(rc,mid+1,r,ti,p);
    t[x]=merge(t[lc],t[rc]);
    return res;
  }
  node qry(int x,int l,int r,int ql,int qr)
  {
    if(ql<=l&&r<=qr)return t[x];
    int mid=l+r>>1,lc=x<<1,rc=lc+1,res=0;
    if(qr<=mid)return qry(lc,l,mid,ql,qr);
    if(ql>mid)return qry(rc,mid+1,r,ql,qr);
    return merge(qry(lc,l,mid,ql,qr),qry(rc,mid+1,r,ql,qr));
  }
}T1,T2;

class seg_tree
{
  void pushdown(int x)
  {
    if(!t[x].tag)return;
    int lc=x<<1,rc=lc+1;
    t[lc].minn+=t[x].tag;t[lc].tag+=t[x].tag;
    t[rc].minn+=t[x].tag;t[rc].tag+=t[x].tag;
    t[x].tag=0; 
  }
  void update(int x)
  {
    int lc=x<<1,rc=lc+1;
    t[x].minn=min(t[lc].minn,t[rc].minn);   
  }
  public:
  info t[N*4];
  void build(int x,int l,int r)
  {
    t[x].minn=l;t[x].tag=0;
    if(l==r)return;
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    build(lc,l,mid);build(rc,mid+1,r);
  }
  void modify(int x,int l,int r,int ql,int qr,int val)
  {
    if(ql<=l&&r<=qr){t[x].minn+=val;t[x].tag+=val;return;}
    int mid=l+r>>1,lc=x<<1,rc=lc+1;
    pushdown(x);
    if(ql<=mid)modify(lc,l,mid,ql,qr,val);
    if(qr>mid)modify(rc,mid+1,r,ql,qr,val);
    update(x);
  }
  int find_l(int x,int l,int r,int pos)
  {
    if(t[x].minn)return 0;
    if(l==r)return l;
    int mid=l+r>>1,lc=x<<1,rc=lc+1,tmp;
    pushdown(x);
    if(pos<=mid){if(tmp=find_l(lc,l,mid,pos))return tmp;}
    return find_l(rc,mid+1,r,pos);
  }
  int find_r(int x,int l,int r)
  {
    if(t[x].minn)return 0;
    if(l==r)return l;
    pushdown(x);
    int mid=l+r>>1,lc=x<<1,rc=lc+1,tmp;
    if(tmp=find_r(rc,mid+1,r))return tmp;
    return find_r(lc,l,mid);
  }
}T;

int main()
{
  int ti,p;char s[5];
  scanf("%d%d",&n,&Q);
  T.build(1,1,n);T1.build(1,1,n);T2.build(1,1,n);
  while(Q--)
  {
    scanf(" %s%d%d",s,&ti,&p);
    if(s[0]=='A')
    {
      int pos=T.find_l(1,1,n,ti);
      if(!pos)
      {
        ans+=p;
        T1.insert(1,1,n,ti,p);
        T.modify(1,1,n,ti,n,-1);
      }
      else
      {
        node x=T1.qry(1,1,n,1,pos);
        if(p>x.minn)
        {
          ans+=p-x.minn;
          T1.erase(1,1,n,x.pos,x.minn);
          T.modify(1,1,n,x.pos,n,1);
          T2.insert(1,1,n,x.pos,-x.minn);
          T1.insert(1,1,n,ti,p);
          T.modify(1,1,n,ti,n,-1);
        }
        else T2.insert(1,1,n,ti,-p);
      } 
    }
    else
    {
      if(!T2.erase(1,1,n,ti,-p))
      {
        ans-=p;
        T1.erase(1,1,n,ti,p);
        T.modify(1,1,n,ti,n,1);
        int pos=T.find_r(1,1,n);
        node x=T2.qry(1,1,n,pos+1,n);
        if(x.minn<=0)
        {
          ans-=x.minn;
          T2.erase(1,1,n,x.pos,x.minn);
          T1.insert(1,1,n,x.pos,-x.minn);
          T.modify(1,1,n,x.pos,n,-1);
        }
      }
    }
    printf("%d\n",ans);
  }
  return 0;
} 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值