均衡队形

来源:互联网 发布:10月金融数据 编辑:程序博客网 时间:2024/04/29 19:13

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 31734251 54 62 2 

样例输出

630
线段树。更新的时候直接更新到叶子节点。查询的时候直接查询区间即可。
下面是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;}



原创粉丝点击