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