AtCoder Beginner Contest 247 E

不知道怎么的,一个简单题我竟然用了很复杂的方法去解决他,分享一下我奇妙的解法(线段树+二分+预处理),估计很少读者能看懂吧?

#include<bits/stdc++.h>
#define int long long 
#define ed '\n'
#define IOS ios::sync_with_stdio(false);cin.tie(0),cout.tie(0);
#define all(x) x.begin(), x.end()
#define lb(x) x&-x
using namespace std;
typedef pair<int,int>pa;
const int mod_=1e18;
const int mod=998244353;
const int g=1e6+10;
int a[g];
struct pp
{
	int id;
	int l;
	int r;
	int mx;
	int mi;
}tr[g];
void build(int i,int l,int r)
{
	tr[i]={i,l,r,0,mod_};
	if(l==r)
	{
	   tr[i].mx=a[l];
	   tr[i].mi=a[l];
	   return;	
	}
	int mid=l+r>>1;
	build(i+i,l,mid);
	build(i+i+1,mid+1,r);
	
	tr[i].mx=max(tr[i+i].mx,tr[i+i+1].mx);
	tr[i].mi=min(tr[i+i].mi,tr[i+i+1].mi);
	
	return;
}
int get_mx(int i,int l,int r)
{
	if(tr[i].l>=l&&r>=tr[i].r)return tr[i].mx;
	
	int mid=tr[i].l+tr[i].r>>1;
	int x=0;
	if(l<=mid)x=max(x,get_mx(i+i,l,r));
	if(r>mid)x=max(x,get_mx(i+i+1,l,r));
	return x;
}
int get_mi(int i,int l,int r)
{
	if(tr[i].l>=l&&r>=tr[i].r)return tr[i].mi;
	
	int mid=tr[i].l+tr[i].r>>1;
	int x=mod_;
	if(l<=mid)x=min(x,get_mi(i+i,l,r));
	if(r>mid)x=min(x,get_mi(i+i+1,l,r));
	return x;
}
void solve()
{ 
    int n=0,x=0,y=0;
    cin>>n>>x>>y;
      
    for(int i=1;i<=n;i++)cin>>a[i];
    
    vector<int>nxt_x(n+2,n+1),nxt_y(n+2,n+1);  
    for(int i=n;i>=1;i--)
    {
		if(a[i]==x)nxt_x[i]=i;
		else nxt_x[i]=nxt_x[i+1];
		
		if(a[i]==y)nxt_y[i]=i;
		else nxt_y[i]=nxt_y[i+1];
	}
	
    build(1,1,n);
    
   auto check=[&](int l,int r)->bool
   {
   	int t1=get_mx(1,l,r),t2=get_mi(1,l,r);
   	if(t1!=x||t2!=y)return true;
   	else return false;
   };
   
    int ans=0;
    for(int i=1;i<=n;i++)
    {
	   if(a[i]==x)
	   {
	   	  int id=nxt_y[i];
	   	  if((id>=n+1)||(get_mi(1,i,id)!=y)||(get_mx(1,i,id)!=x))continue;
	   	  else 
	   	  {
		     int l=id,r=n;
			 while(l<r)
			 {
			 	int mid=(l+r+1)>>1;
			 	if(check(i,mid))r=mid-1;
			 	else l=mid;
			 }	 	
			 ans+=r-id+1;
		  }
	   }
	   else if(a[i]==y)
	   {
	   	   int id=nxt_x[i];
	   	   if((id>=n+1)||(get_mi(1,i,id)!=y)||(get_mx(1,i,id)!=x))continue;
	   	   else 
	   	   {
			  	int l=id,r=n;
			  	while(l<r)
			  	{
				  	int mid=(l+r+1)>>1;
				  	if(check(i,mid))r=mid-1;
				  	else l=mid;
				}
				  ans+=r-id+1;
			}
	   }
	   else 
	   {
	   	  int id1=nxt_x[i],id2=nxt_y[i];
	   	  int id=max(id1,id2);
	   	  if((id>=n+1)||(get_mi(1,i,id)!=y)||(get_mx(1,i,id)!=x))continue;
	   	  else 
		 {
		   	int l=id,r=n;
		   	while(l<r)
		   	{
		   		int mid=(l+r+1)>>1;
		   		if(check(i,mid))r=mid-1;
		   		else l=mid;
		   	}
		   	ans+=r-id+1;
		}  	   	  
	   }
 	}
 	cout<<ans<<ed;
 
   return;    
}
signed main()
{ 

  IOS;

 // freopen("in.txt","r",stdin);
 //freopen("zheng.txt","w",stdout);

  int t=1;
  
   //cin>>t;
  
  while(t--)
  {
    solve();
  }


  return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值