hdu6701 Make Rounddog Happy(2019hdu多校第十场1011)

1 篇文章 0 订阅
1 篇文章 0 订阅
【题目描述】

传送带
求使得max(al,al+1,…,ar)-(r-l+1)<=k的区间数目

【思路】

分治
预处理每个数小于它且互不相等的最左端和最右端
找跨过这个数的区间数目(按照长度较短的那一段枚举)
预处理有两种方式,RMQ倍增或者用单调栈来维护
其中互不相等可以用lst数组来实现
分治也有两种形式,普通的分治或者启发式分治
我用的是单调栈+普通分治
RMQ+启发式分治可见该博客传送带

【代码】
#include <iostream>
#include <string.h>
#include <queue>
#include <stdlib.h>
#include <stdio.h>
#include <stack>
#include <queue>
#include <cmath>
#include <algorithm>
using namespace std;
#define loop(i, x) for(int i = 0; i < x; ++i)
#define circle(i, st, en) for(int i = st; i <= en; ++i)
#define reverse(i, st, en) for(int i = st; i >= en; --i)
#define wh(t) while(t--)
#define mem(i, x) memset(i, x, sizeof(i))
#define ssc(x) scanf("%s", s)
#define dsc(x) scanf("%lld", &x)
#define lfsc(x) scanf("%lf", &x)
typedef long long ll;
const int MAXN=3e5+10;
const ll P=1e9+7;
const double eps=1e-10;
const double pi=acos(-1.0);
const int INF=0x3f3f3f3f;
int T;
int n,k;
int f[MAXN];
int a[MAXN];
int llst[MAXN];
int rlst[MAXN];
int pre[MAXN];
int lpos[MAXN];
int rpos[MAXN];
struct node{
	int num;
	int pos;
	node(){}node(int num_,int pos_){num=num_;pos=pos_;}
};
stack<node> s;
ll solve(int l,int r){
	if(l<=r) return r-l+1;
	return 0;
}
ll dfs(int l,int r){
	if(l>r) return 0;
	int mid=(l+r)>>1;
	ll res=0;
	int lim=max(a[mid]-k,1);
	if(mid-lpos[mid]>rpos[mid]-mid){
		reverse(i,rpos[mid],mid)
			res+=solve(max(llst[i],lpos[mid]),min(mid,i-lim+1));
	}
	else{
		circle(i,lpos[mid],mid)
			res+=solve(max(mid,i+lim-1),min(rlst[i],rpos[mid]));
	}
	res+=dfs(l,mid-1);
	res+=dfs(mid+1,r);
	return res;
}
int main(){
	scanf("%d",&T);
	wh(T){
		scanf("%d%d",&n,&k);
		while(!s.empty()) s.pop();
		loop(i,MAXN) pre[i]=0;
		circle(i,1,n){
		    scanf("%d",&a[i]);
		    llst[i]=pre[a[i]]+1,pre[a[i]]=i;
		}
		circle(i,1,n){
			int pos=i;
			llst[i]=max(llst[i],llst[i-1]);
		    while(!s.empty()&&s.top().num<=a[i]){
			    pos=s.top().pos;
				s.pop();	
			} 
			s.push(node(a[i],pos));
			lpos[i]=max(pos,llst[i]);
		}
		while(!s.empty()) s.pop();
		loop(i,MAXN) pre[i]=n+1;
		reverse(i,n,1) rlst[i]=pre[a[i]]-1,pre[a[i]]=i;
		rlst[n+1]=n+1;
		reverse(i,n,1){
			int pos=i;
			rlst[i]=min(rlst[i],rlst[i+1]);
			while(!s.empty()&&s.top().num<=a[i]){
				pos=s.top().pos;
				s.pop();
			}
			s.push(node(a[i],pos));
			rpos[i]=min(pos,rlst[i]);
		}
		printf("%lld\n",dfs(1,n));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值