zoukankan      html  css  js  c++  java
  • 题解[51nod1555] 布丁怪

    题解[51nod1555] 布丁怪

    题面

    解析

    本文参考这位dalao的题解

    首先有一个巧妙的转换,

    开一个数组记录每个横坐标的纵坐标,

    简单来说就是对于点(x,y),令a[x]=y.

    于是问题就变成了求满足区间最大值与最小值的差恰好等于区间长度的区间数.

    于是可以考虑分治不要问我怎么想到的

    设当前区间为l,r,中点为mid.

    mx[i]=i~mid的最大值(l<=mid),mid+1到i的最大值(i>mid)

    mn[i]同理.

    分情况讨论:

    1.区间最大值和最小值都在左边.

    设右端点为j,这时候j要满足mn[j+1]<mn[i]或mx[j+1]>mx[i],否则j+1也在mn~mx这个范围里面,j肯定不能是端点.

    然后再看j-i是否等于mx[i]-mn[i].

    2.最大值在左边,最小值在右边.

    因为mx和mn都是单调的,所以拿两个指针L和R维护满足要求的右端点,

    然后设右端点为j,则mx[i]-mn[j]=j-i,

    即mx[i]+i=mn[j]+j,

    开个桶维护一下就行了.

    code:

    #include <iostream>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define ll long long
    #define fre(x) freopen(x".in","r",stdin),freopen(x".out","w",stdout)
    using namespace std;
    
    inline int read(){
    	int sum=0,f=1;char ch=getchar();
    	while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
    	while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
    	return f*sum;
    }
    
    const int N=1000005;
    int n,a[N];ll ans,cnt[N];
    int mx[N],mn[N];
    
    inline void work(int l,int r,int m){
    	mx[m]=mn[m]=a[m];
    	for(int i=m-1;i>=l;i--){
    		mx[i]=max(mx[i+1],a[i]);
    		mn[i]=min(mn[i+1],a[i]);
    	}
    	mx[m+1]=mn[m+1]=a[m+1];
    	for(int i=m+2;i<=r;i++){
    		mx[i]=max(mx[i-1],a[i]);
    		mn[i]=min(mn[i-1],a[i]);
    	}
    	int L=m+1,R=m,j=m;
    	for(int i=m;i>=l;i--){
    		while(j<r&&mx[j+1]<mx[i]&&mn[j+1]>mn[i]) j++;
    		if(mx[i]-mn[i]==j-i&&j>m) ans++;
    		while(R<r&&mx[R+1]<mx[i]) R++,cnt[R+mn[R]]++;
    		while(L<=r&&mn[L]>mn[i]) cnt[L+mn[L]]--,L++;
    		if(L<=R) ans+=cnt[i+mx[i]];
    	}
    	while(L<=r) cnt[L+mn[L]]--,L++;
    	while(R<r) R++,cnt[R+mn[R]]++;
    }
    
    inline void solve(int l,int r){
    	if(l==r){ans++;return ;}
    	int mid=(l+r)>>1;
    	solve(l,mid);solve(mid+1,r);
    	work(l,r,mid);
    	reverse(a+l,a+r+1);
    	if((r-l+1)%2) mid--;
    	work(l,r,mid);
    	reverse(a+l,a+r+1);
    }
    
    signed main(){
    	n=read();
    	for(int i=1;i<=n;i++)
    	{int x=read();a[x]=read();}
    	solve(1,n);	
    	printf("%lld
    ",ans);
    	return 0;
    }
    
  • 相关阅读:
    C++11特性
    DBC文件小结
    关于宏定义
    CentOS 6.5下Zabbix的安装配置
    CentOS下搭建LAMP环境详解
    VS2010中汉字拷贝到Word出现乱码问题解决
    DLL注入
    数组赋值
    CDC的StretchBlt函数载入位图时图片失真问题
    2019年下半年Web前端开发初级理论考试
  • 原文地址:https://www.cnblogs.com/zsq259/p/11848492.html
Copyright © 2011-2022 走看看