刚学最值分治求助
查看原帖
刚学最值分治求助
631787
Watanabe楼主2024/1/9 10:32

3e5那个点t了,怀疑是分治写假了,求带师指导一下

做法是预处理每个数的下一个出现位置,用线段树查询下一个出现位置的最小值判断是否合法

#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define re register

using namespace std;
const int N=3e5+10,INF=1e9+1;
int n,a[N];

int t[N<<2];
int pre[N],nxt[N];
inline void up(int x)
{
	t[x]=min(t[x<<1],t[x<<1|1]);
}
void build(int x,int l,int r)
{
	if(l==r)
	{
		t[x]=nxt[l];
		return ;
	}
	int mid=l+r>>1;
	build(x<<1,l,mid),build(x<<1|1,mid+1,r);
	up(x);
}
int ask(int x,int l,int r,int ql,int qr)
{
	if(l>=ql&&r<=qr) return t[x];
	int mid=l+r>>1,ret=INF;
	if(ql<=mid) ret=min(ret,ask(x<<1,l,mid,ql,qr));
	if(mid<qr) ret=min(ret,ask(x<<1|1,mid+1,r,ql,qr));
	return ret;
}
int ans;

void solve(int l,int r)
{
	if(l>r) return ;
	if(l==r)
	{
		ans+=(a[l]==1);
		return ;
	}
    int mid=l;
    for(re int i=l+1;i<=r;++i) mid= a[i]>a[mid] ? i : mid; 
    if(mid<=(l+r>>1))
    {
    	for(re int i=mid;i>=l;--i)
    	{
    		if(mid-i+1>a[mid]) break ;
    		if(i+a[mid]-1>r) continue ;
    		ans+= ask(1,1,n,i,i+a[mid]-1)>i+a[mid]-1 ;
    	//	cout<<mid<<" "<<ask(1,1,n,i,i+a[mid]-1)<<"\n";
		}
	}
	else
	{
		for(re int i=mid;i<=r;++i)
		{
			if(i-mid>a[mid]) break ;
			if(i-a[mid]+1<l) continue ;
			ans+= ask(1,1,n,i-a[mid]+1,i)>i ;
		}
	}
//	cout<<mid<<" "<<ans<<"\n";
	solve(l,mid-1),solve(mid+1,r);
}

inline int read(){char cr=getchar();int x_=0,fui=1;while(cr<48){if(cr=='-')fui=-1;cr=getchar();}while(cr>47)x_=(x_*10)+(cr^48),cr=getchar();return x_*fui;}
inline void mwrite(int aq){if(aq>9)mwrite(aq/10);putchar((aq%10)|48);}
inline void write(int af,char cr){mwrite(af<0?(putchar('-'),af=-af):af);putchar(cr);}

signed main()
{
	n=read();
	for(re int i=1;i<=n;++i) a[i]=read(),nxt[i]=INF;
	for(re int i=1;i<=n;++i) 
	{
	//	if(!pre[a[i]]) pre[a[i]]=i;
		if(pre[a[i]]) nxt[pre[a[i]]]=i;
		pre[a[i]]=i;
	}
	build(1,1,n);
	solve(1,n);
	write(ans,' ');
	return 0;
}
2024/1/9 10:32
加载中...