玲珑杯 1149 - Buildings【线段树+尺取】

“玲珑杯”ACM比赛 Round #19


题意:
给出n,k值,接下来一行是楼房的高度(序列不能排序),按照题中的公式求取满足条件的楼房对数;
思路:
本题无非是更新区间最大值,最小值,其次利用尺取的思想。每更新一个值(也就是r向前移动一位)就查询一次,满足条件时:sum += r - l (比赛时最小值查询写错了,好菜啊)

#include<bits/stdc++.h>
using namespace std;

int p[2000000+10];

struct record
{
    int left,right,ma,mi;
}num[2000000+10];

int buildmin(int left,int right,int node)
{
    int mid;
    num[node].left=left;
    num[node].right=right;
    if(left==right)
    {
        return num[node].mi=p[left];
    }
    mid=(left+right)>>1;
    return num[node].mi=min(buildmin(left,mid,node*2),buildmin(mid+1,right,node*2+1));
}

int buildmax(int left,int right,int node)
{
    int mid;
    num[node].left=left;
    num[node].right=right;
    if(left==right)
    {
        return num[node].ma=p[left];
    }
    mid=(left+right)>>1;
    return num[node].ma=max(buildmax(left,mid,node*2),buildmax(mid+1,right,node*2+1));
}

int querymin(int left,int right,int node)//求最小值 
{
    int mid;
    if(num[node].left==left && num[node].right==right)
    {
        return num[node].mi;
    }
    mid=(num[node].left+num[node].right)>>1;
    if(right<=mid)
    {
        return querymin(left,right,node*2);
    }
    else
    {
        if(left>mid)
        {
            return querymin(left,right,node*2+1);
        }
        else
        {
            return min(querymin(left,mid,node*2),querymin(mid+1,right,node*2+1));
        }
    }
}

int querymax(int left,int right,int node)//求最大值 
{
    int mid;
    if(num[node].left==left&&num[node].right==right)
    {
        return num[node].ma;
    }
    mid=(num[node].left+num[node].right)>>1;
    if(right<=mid)
    {
        return querymax(left,right,node*2);
    }
    else
    {
        if(left>mid)
        {
            return querymax(left,right,node*2+1);
        }
        else
        {
            return max(querymax(left,mid,node*2),querymax(mid+1,right,node*2+1));
        }
    }
}

int main()
{
    int t,n,m,i,j,k;
    int a,b,c;
    scanf("%d %d",&n,&k);
    for(i=1;i<=n;i++)
        scanf("%d",&p[i]);
    buildmin(1,n,1);
    buildmax(1,n,1);
    int l=1,r=1,cnt1,cnt2;
    int sum=0;
    for(int i=1;i<=n;i++)
    {
        r=i;
        sum++;
        cnt1=querymax(l,r,1);
        cnt2=querymin(l,r,1);
    //  printf("#%d %d#\n",cnt1,cnt2);
        if(cnt1-cnt2<=k)
        {
            sum+=r-l;
    //      printf("*%d -> %d*\n",l,r);
        }
        else
        {
            while(cnt1-cnt2>k)
            {
                l++;
                cnt1=querymax(l,r,1);
                cnt2=querymin(l,r,1);
//              printf("%d -> %d\n",l,r);
            }
            sum+=r-l;
        }
    }
    printf("%lld\n",sum);
    return 0;
} 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值