zoukankan      html  css  js  c++  java
  • VIjos——V 1782 借教室 | | 洛谷——P1083 借教室

    https://vijos.org/p/1782||

    https://www.luogu.org/problem/show?pid=1083

    描述

    在大学期间,经常需要租借教室。大到院系举办活动,小到学习小组自习讨论,都需要向学校申请借教室。教室的大小功能不同,借教室人的身份不同,借教室的手续也不一样。

    面对海量租借教室的信息,我们自然希望编程解决这个问题。我们需要处理接下来n天的借教室信息,其中第i天学校有ri个教室可供租借。共有m份订单,每份订单用三个正整数描述,分别为dj,sj,tj,表示某租借者需要从第sj天到第tj天租借教室(包括第sj天和第tj天),每天需要租借dj个教室。 
    我们假定,租借者对教室的大小、地点没有要求。即对于每份订单,我们只需要每天提供dj个教室,而它们具体是哪些教室,每天是否是相同的教室则不用考虑。

    借教室的原则是先到先得,也就是说我们要按照订单的先后顺序依次为每份订单分配教室。如果在分配的过程中遇到一份订单无法完全满足,则需要停止教室的分配,通知当前申请人修改订单。这里的无法满足指从第sj天到第tj天中有至少一天剩余的教室数量不足dj个。

    现在我们需要知道,是否会有订单无法完全满足。如果有,需要通知哪一个申请人修改订单。

    格式

    输入格式

    第一行包含两个正整数n,m,表示天数和订单的数量。 
    第二行包含n个正整数,其中第i个数为ri,表示第i天可用于租借的教室数量。 
    接下来有m行,每行包含三个正整数dj,sj,tj,表示租借的数量,租借开始、结束分别在第几天。 
    每行相邻的两个数之间均用一个空格隔开。天数与订单均用从1开始的整数编号。

    输出格式

    如果所有订单均可满足,则输出只有一行,包含一个整数0。否则(订单无法完全满足)输出两行,第一行输出一个负整数-1,第二行输出需要修改订单的申请人编号。

    样例1

    样例输入1

    4 3 
    2 5 4 3 
    2 1 3 
    3 2 4 
    4 2 4 
    

    样例输出1

    -1
    2
    

    限制

    每个测试点1s

    提示

    对于10%的数据,有1≤ n,m≤ 10; 
    对于30%的数据,有1≤ n,m≤1000; 
    对于70%的数据,有1≤ n,m≤ 10^5; 
    对于100%的数据,有1≤n,m≤10^6,0≤ri,dj≤10^9,1≤sj≤tj≤n。

    来源

    Noip2012提高组复赛Day2T2

    线段树 维护区间最小值,如果最小值不满足需要结束、、线段树区间操作

     1 #include <algorithm>
     2 #include <cstdio>
     3 
     4 using namespace std;
     5 
     6 const int N(1000000+15);
     7 int n,m,i,num,sta,ove;
     8 
     9 struct Tree
    10 {
    11     int l,r,num,flag;
    12 }tree[N<<2];
    13 
    14 inline void read(int &x)
    15 {
    16     x=0;register char ch=getchar();
    17     for(;ch<'0'||ch>'9';) ch=getchar();
    18     for(;ch>='0'&&ch<='9';ch=getchar())
    19         x=x*10+ch-'0';
    20 }
    21 
    22 void Tree_build(int now,int l,int r)
    23 {
    24     tree[now].l=l; tree[now].r=r;
    25     if(l==r)
    26     {
    27         read(tree[now].num);
    28         return ;
    29     }
    30     int mid=tree[now].l+tree[now].r>>1;
    31     Tree_build(now<<1,l,mid);
    32     Tree_build(now<<1|1,mid+1,r);
    33     tree[now].num=min(tree[now<<1].num,tree[now<<1|1].num); 
    34 } 
    35 
    36 inline void Tree_down(int now)
    37 {
    38     tree[now<<1].num-=tree[now].flag;
    39     tree[now<<1].flag+=tree[now].flag;
    40     tree[now<<1|1].num-=tree[now].flag;
    41     tree[now<<1|1].flag+=tree[now].flag;
    42     tree[now].flag=0;
    43 }
    44 void Tree_change(int now,int l,int r,int x)
    45 {
    46     if(tree[now].l>=l&&tree[now].r<=r)
    47     {
    48         if(tree[now].num<x)
    49         {
    50             printf("-1
    %d",i);
    51             exit(0);
    52         }
    53         tree[now].flag+=x;
    54         tree[now].num-=x;
    55         return ;
    56     }
    57     if(tree[now].flag) Tree_down(now);
    58     int mid=tree[now].l+tree[now].r>>1;
    59     if(mid>=r) Tree_change(now<<1,l,r,x);
    60     else if(mid<l) Tree_change(now<<1|1,l,r,x);
    61     else
    62     {
    63         Tree_change(now<<1,l,mid,x);
    64         Tree_change(now<<1|1,mid+1,r,x);
    65     }
    66     tree[now].num=min(tree[now<<1].num,tree[now<<1|1].num);
    67 }
    68 
    69 int main()
    70 {
    71     read(n); read(m);
    72     Tree_build(1,1,n);
    73     for(i=1;i<=m;i++)
    74     {
    75         read(num);read(sta);read(ove);
    76         Tree_change(1,sta,ove,num);
    77     }
    78     puts("0");
    79     return 0;
    80 }
    View Code

    正解:二分+差分

     1 #include <algorithm>
     2 #include <cstring>
     3 #include <cstdio>
     4 
     5 using namespace std;
     6 
     7 const int N(1000000+15);
     8 int n,m,room[N],num[N],sta[N],ove[N];
     9 
    10 int if_,ch;
    11 void read(int &x)
    12 {
    13     if_=x=0; ch=getchar();
    14     for(;ch<'0'||ch>'9';ch=getchar())
    15         if(ch=='-') if_=1;
    16     for(;ch>='0'&&ch<='9';ch=getchar())
    17         x=x*10+ch-'0';
    18     if(if_) x=(~x)+1;
    19 }
    20 
    21 int s[N],ans;
    22 bool jud(int day)
    23 {
    24     memset(s,0,sizeof(s));
    25     for(int i=1;i<=day;i++)
    26     {
    27         s[sta[i]]+=num[i];
    28         s[ove[i]+1]-=num[i];
    29     }
    30     int sum=0;
    31     for(int i=1;i<=n;i++)
    32     {
    33         sum+=s[i];
    34         if(sum>room[i])
    35             return false;
    36     }
    37     return true;
    38 }
    39 
    40 void Dichotomy()
    41 {
    42     int l=1,r=m;
    43     for(;l<=r;)
    44     {
    45         int mid=l+r>>1;
    46         if(!jud(mid))
    47         {
    48             ans=mid;
    49             r=mid-1;
    50         }
    51         else l=mid+1;
    52     }
    53 }
    54 
    55 int main()
    56 {
    57     read(n); read(m);
    58     for(int i=1;i<=n;i++) read(room[i]);
    59     for(int i=1;i<=m;i++)
    60         read(num[i]),read(sta[i]),read(ove[i]);
    61     Dichotomy();
    62     if(ans) puts("-1");
    63     printf("%d",ans);
    64     return 0;
    65 }
    正解
    ——每当你想要放弃的时候,就想想是为了什么才一路坚持到现在。
  • 相关阅读:
    349. 两个数组的交集
    383. 赎金信
    242. 有效的字母异位词
    844. 比较含退格的字符串
    904. 水果成篮
    剑指offer(9)变态跳台阶
    剑指offer(8)跳台阶
    剑指offer(7)斐波那契数列
    剑指offer(6)旋转数组的最小数字
    剑指offer(5)用两个栈实现队列
  • 原文地址:https://www.cnblogs.com/Shy-key/p/6979932.html
Copyright © 2011-2022 走看看