题面
题目描述
小明这些天一直在思考这样一个奇怪而有趣的问题:
在1~N的某个全排列中有多少个连号区间呢?这里所说的连号区间的定义是:
如果区间[L, R] 里的所有元素(即此排列的第L个到第R个元素)递增排序后能得到一个长度为R-L+1的“连续”数列,则称这个区间连号区间。
当N很小的时候,小明可以很快地算出答案,但是当N变大的时候,问题就不是那么简单了,现在小明需要你的帮助。
输入格式:
第一行是一个正整数N (1 <= N <= 50000), 表示全排列的规模。
第二行是N个不同的数字Pi(1 <= Pi <= N), 表示这N个数字的某一全排列。
输出格式:
输出一个整数,表示不同连号区间的数目。
示例:
用户输入:
4
3 2 4 1
程序应输出:
7
用户输入:
5
3 4 2 5 1
程序应输出:
9
解释:
第一个用例中,有7个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [2,2], [3,3], [4,4]
第二个用例中,有9个连号区间分别是:[1,1], [1,2], [1,3], [1,4], [1,5], [2,2], [3,3], [4,4], [5,5]
分析
时间复杂度:O(nlogn)
性质分析:一个区间为连号区间[l,r],等价于这个区间中,最大值mx-最小值mi=r-l。记vi=mx-mi+l,我们枚举区间的右端点r,对于每一个l(l>=1&&l<=r-1)维护在区间[l,r]的vi。其中[i,r]的值可以由[i,r-1]变换而来,当r是其中的最大值时,加上a[r]-a[r-1]的差值,当r是其中的最小值时,加上a[r-1]-a[r]。我们用单调栈st1来存储区间的最大值的元素下标,栈中两个相邻的元素w,w+1代表在st1[w]+1与st1[w+1]这个区间的内的i,有区间[i,r]最大值为a[st1[w+1]]。区间最小值的维护同上。当我们计算完每个区间的vi时,只要统计与r相等的vi数量即可,但是线段树并不支持区间修改和个数统计同时进行。注意到:vi>=r,也就是说r是所有vi的最小值而且这个最小值一定存在(对于从右端点为r的情况,至少存在一个[r,r]区间满足条件),我们使用线段树统计最小值的个数即可得出结果。
使用数据结构:两个单调栈st1,st2维护区间的最大值和最小值,一个维护区间最小值数量的线段树
AC代码:
import java.awt.image.ComponentSampleModel;
import java.io.*;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.math.RoundingMode;
import java.util.*;
public class Main {
final static int M=(int) 50+5;
final static int N=(int) 5e4+5;
final static int MOD=(int) 50+5;
final static int BIG=(int)21e8+5;
final static Main main=new Main();
static int[] a=new int[N];
static int[] st1=new int[N];
static int[] st2=new int[N];
class Data implements Comparable<Data>,Cloneable{
public int val,num;
@Override
public int compareTo(Data o) {
return (int) (val-o.val);
}
public Data add(Data o){
num+=o.num;
return this;
}
public Data(int val, int num) {
this.val = val;
this.num = num;
}
public Data() {
}
@Override
protected Data clone(){
try {
super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
Data d=new Data(val,num);
return d;
}
}
class Node{
int l,r;
int lz;
Data data;
}
static Node[] nd=new Node[4*N];
static void push_back(int i){
Data a,b;
a=nd[2*i].data.clone();
b=nd[2*i+1].data.clone();
if(a.compareTo(b)<0){
nd[i].data=a;
} else if (a.compareTo(b) == 0) {
nd[i].data=a.add(b);
}else {
nd[i].data=b;
}
}
static void push_down(int i){
Node n=nd[i];
if(n.lz!=0){
nd[2*i].lz+=n.lz;
nd[2*i+1].lz+=n.lz;
nd[2*i].data.val+=n.lz;
nd[2*i+1].data.val+=n.lz;
n.lz=0;
}
}
static void make(int i,int l,int r){
nd[i]=main.new Node();
nd[i].l=l;
nd[i].r=r;
if(l==r){
nd[i].data=main.new Data(l,1);
return;
}
int mid=(l+r)/2;
make(2*i,l,mid);
make(2*i+1,mid+1,r);
push_back(i);
}
static void update(int i,int l,int r,int val){
Node n=nd[i];
if(n.l>r||n.r<l) return;
if(n.l>=l&&n.r<=r){
n.data.val+=val;
n.lz+=val;
return;
}
push_down(i);
if(l<=nd[2*i].r){
update(2*i,l,r,val);
}
if(r>=nd[2*i+1].l){
update(2*i+1,l,r,val);
}
push_back(i);
}
static Data query(int i,int l,int r){
Node n=nd[i];
if(n.l>=l&&n.r<=r){
return n.data;
}
Data ans=main.new Data(BIG,0);;
if(n.l>r||n.r<l){
return ans;
}
push_down(i);
Data a,b;
a=main.new Data(BIG,0);
b=main.new Data(BIG,0);
if(l<=nd[2*i].r){
a=query(2*i,l,r).clone();
}
if(r>=nd[2*i+1].l){
b=query(2*i+1,l,r).clone();
}
if(a.compareTo(b)<0) ans=a;
else if (a.compareTo(b) == 0) {
ans=a.add(b);
}else {
ans=b;
}
push_back(i);
return ans;
}
class Pair implements Comparable<Pair>{
public int len;
public int value;
@Override
public int compareTo(Pair o) {
if(o.value!=value){
return value-o.value;
}else {
return o.len - len;
}
}
}
public static void main(String[] args) throws IOException{
Input sc=main.new Input();
PrintWriter out =new PrintWriter(new OutputStreamWriter(System.out));
long ans=0;
int n;
n= sc.nextInt();
make(1,1,n);
int top1,top2;
top1=0;
top2=0;
for(int i=1;i<=n;i++){
a[i]= sc.nextInt();
while (top1!=0&&a[st1[top1]]<=a[i]){
update(1,st1[top1-1]+1,st1[top1],a[i]-a[st1[top1]]);
top1--;
}
st1[++top1]=i;
while (top2!=0&&a[st2[top2]]>=a[i]){
update(1,st2[top2-1]+1,st2[top2],a[st2[top2]]-a[i]);
top2--;
}
st2[++top2]=i;
Data d=query(1,1,i);
ans+=d.num;
}
out.println(ans);
out.close();
}
class Input {
public BufferedReader reader;
public StringTokenizer tokenizer;
public Input() {
try {
if (System.getProperty("ONLINE_JUDGE")==null) {
reader = new BufferedReader(new FileReader("C:\\Users\\Limhuang\\IdeaProjects\\BlueBrige\\src\\main\\resources\\org\\example\\in.txt"));
} else {
reader = new BufferedReader(new InputStreamReader(System.in));
}
}catch (Exception e){
reader = new BufferedReader(new InputStreamReader(System.in));
}
tokenizer = null;
}
public String next() {
while (tokenizer == null || !tokenizer.hasMoreTokens()) {
try {
tokenizer = new StringTokenizer(reader.readLine());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return tokenizer.nextToken();
}
public String nextLine() {
String str = null;
try {
str = reader.readLine();
} catch (IOException e) {
e.printStackTrace();
}
return str;
}
public int nextInt() {
return Integer.parseInt(next());
}
public long nextLong() {
return Long.parseLong(next());
}
public Double nextDouble() {
return Double.parseDouble(next());
}
public BigInteger nextBigInteger() {
return new BigInteger(next());
}
}
}