均衡队形

182. [USACO Jan07] 均衡队形

★★   输入文件: lineup.in   输出文件: lineup.out    简单对比
时间限制:1 s   内存限制:128 MiB

题目描述

农夫约翰的 N (1 ≤ N ≤ 50,000) 头奶牛,每天挤奶时总会按同样的顺序站好。一日,农夫约翰决定为奶牛们举行一个“终极飞盘”比赛。为简化问题,他将从奶牛队列中选出一个连续区间来进行游戏。不过,参加游戏的奶牛要玩的开心的话就不能在身高上差距太大。

农夫约翰制定了 Q (1 ≤ Q ≤ 200,000) 个预定的参赛组,给出它们的身高 (1 ≤ 身高 ≤ 1,000,000)。对每个参赛组,他需要你帮助确定组中最高牛和最低牛的身高差。

输入格式

  • 第 1 行: 两个空格隔开的整数,N 和 Q。
  • 第 2..N+1 行: 第 i+1 行包含一个整数表示第 i 头牛的身高。
  • 第 N+2..N+Q+1 行: 两个整数 A 和 B (1 ≤ A ≤ B ≤ N),表示一个从 A 到 B 的参赛组区间。

输出格式

  • 第 1..Q 行: 每行包含一个整数来表示区间上最大身高差。

样例输入

6 3
1
7
3
4
2
5
1 5
4 6
2 2 

样例输出

6
3
0
 
 
线段树。更新的时候直接更新到叶子节点。查询的时候直接查询区间即可。
 
 
下面是AC代码:
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn = 50000+10;
int a[maxn];
struct node{
    int l,r,m;
    int max,min;
    int h;
}T[maxn<<2];
void build(int id ,int l,int r){
    T[id].l=l;T[id].r=r;T[id].max=-1;
    T[id].min=1000010;
    T[id].h=0;  T[id].m=(l+r)>>1;
    if(l==r) return ;
    int m=T[id].m;
    build(id<<1,l,m);  build(id<<1|1,m+1,r);
}
void update(int id,int l,int r,int h){
    if(T[id].max<h)  T[id].max=h;
    if(T[id].min>h)  T[id].min=h;

    if(T[id].l==l&&T[id].r==r){
         T[id].max=T[id].min=T[id].h=h;
         return ;
     }
     int m=T[id].m;
     if(m>=r) update(id<<1,l,r,h);
     else     update(id<<1|1,l,r,h);
}
int query_max(int id,int l,int r){
    if(T[id].l==l&&T[id].r==r){
       return T[id].max;
    }
    int m=T[id].m;
    if(m>=r)     return query_max(id<<1,l,r);
    else if(m<l) return query_max(id<<1|1,l,r);
    else{
        return max( query_max(id<<1,l,m),query_max(id<<1|1,m+1,r));
    }
}
int query_min(int id,int l,int r){
      if(T[id].l==l&&T[id].r==r){
       return T[id].min;
    }
    int m=T[id].m;
    if(m>=r)  return query_min(id<<1,l,r);
    else if(m<l) return query_min(id<<1|1,l,r);
    else{
        return min( query_min(id<<1,l,m),query_min(id<<1|1,m+1,r));
    }
}
int main(){
    freopen("lineup.in","r",stdin);
    freopen("lineup.out","w",stdout);
    int n,q,l,r;
    scanf("%d%d",&n,&q);
    for(int i=1;i<=n;i++)  scanf("%d",&a[i]);
    build(1,1,n);
    for(int i=1;i<=n;i++){
        update(1,i,i,a[i]);
    }
    //printf("%d\n",a[3]);
    for(int i=0;i<q;i++) {
        scanf("%d%d",&l,&r);
        printf("%d\n",query_max(1,l,r)-query_min(1,l,r));
    }
    return 0;

}

  
  

265. 线段覆盖

★★☆   输入文件: xdfg.in   输出文件: xdfg.out    简单对比
时间限制:2 s   内存限制:20 MiB

【问题描述】

有一根长度为 L 的白色条状物。有两种操作:

  1. 用一条长度为 T 的黑布盖住条状物的 [a, a+T] 这个区间 (0<=a, T<=L) 。
  2. 把某条黑布拿走。

输入 L 和 n 次操作,要你输出每次操作之后:

  1. 条状物上有多少个黑区间。
  2. 条状物上黑区间的总长度。

【输入格式】

输入文件第一行两个整数L(1<=L<=200000), n(1<=n<=200000)

以下有n行,第2--n+1行每行有3个整数m,a,T,m表示操作类型,1表示放入黑布,2表示拿走黑布,a,T表示黑布在L上的起始位置与长度,拿走的黑布保证是原来已经存在的.

【输出格式】

输出有n行,每行两个整数x,y,x表示L上的黑区间个数,y表示黑区间的总长度.

【输入输出样例】
 
输入:

20 4 
1 5 3 
1 7 2 
2 5 3 
1 16 3

输出:

1 3
1 4
1 2
2 5

同上。
下面是AC代码;
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn  = 1000000+10;
int a[maxn];
struct node{
    int l,r,m;
    int h,max;
}T[maxn<<2];
void build(int id,int l,int r){
    T[id].l=l;T[id].r=r;T[id].m=(l+r)>>1; T[id].h=0; T[id].max=-1;
    if(l==r) return;
    int m=T[id].m;
    build(id<<1,l,m); build(id<<1|1,m+1,r);
}
void update(int id,int l,int r,int h){
    if(T[id].max<h)  T[id].max=h;
    if(T[id].l==l&&T[id].r==r){
        T[id].h=h; return;
    }
    int m=T[id].m;
    if(m>=r)  update(id<<1,l,r,h);
    else      update(id<<1|1,l,r,h);
}
int query(int id,int l,int r){
    if(T[id].l==l&&T[id].r==r){
        return T[id].max;
    }
    int m=T[id].m;
    if(m>=r)      return query(id<<1,l,r);
    else if(m<l)  return query(id<<1|1,l,r);
    else{
        return  max(query(id<<1,l,m),query(id<<1|1,m+1,r));
    }
}
int main(){
    freopen("climb.in","r",stdin);
    freopen("climb.out","w",stdout);
    int n,q,l,r;
    scanf("%d",&n);
    build(1,1,n+1);
    for(int i=1;i<=n+1;i++)   scanf("%d",&a[i]),update(1,i,i,a[i]);

    scanf("%d",&q);
    for(int i=0;i<q;i++){
       scanf("%d%d",&l,&r);  l++;r++;
       printf("%d\n",query(1,l,r));
    }
    return 0;

}



 
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值