【CF1083D】The Fair Nut's getting crazy(线段树)(单调栈)

传送门


题解:

p r e [ i ] pre[i] pre[i]表示位置 i i i出现的数上一次出现的位置+1, n x t [ i ] nxt[i] nxt[i]表示位置 i i i出现的数下一次的出现位置-1,那么设 a < b < c < d a<b<c<d a<b<c<d,则一对合法的 b , c b,c b,c确定之后 a a a的合法取值就是 b − max ⁡ ( p r e [ b : c ] ) b-\max(pre[b:c]) bmax(pre[b:c]) d d d的合法取值就是 min ⁡ ( n x t [ b : c ] ) − c \min(nxt[b:c])-c min(nxt[b:c])c,乘上,展开,分别维护,单调栈用于维护最大值最小值,然后用线段树支持更新,没了。


代码:

#include<bits/stdc++.h>
#define ll long long
#define re register
#define cs const

namespace IO{
	inline char gc(){
		static cs int Rlen=1<<22|1;
		static char buf[Rlen],*p1,*p2;
		return (p1==p2)&&(p2=(p1=buf)+fread(buf,1,Rlen,stdin),p1==p2)?EOF:*p1++;
	}
	
	template<typename T>
	inline T get(){
		char c;T num;bool f=0;
		while(!isdigit(c=gc()))f=c=='-';num=c^48l;
		while(isdigit(c=gc()))num=(num+(num<<2)<<1)+(c^48);
		return f?-num:num;
	}
	inline int gi(){return get<int>();}
}
using namespace IO;

using std::cerr;
using std::cout;

cs int mod=1e9+7;
inline int add(int a,int b){a+=b-mod;return a+(a>>31&mod);}
inline int dec(int a,int b){a-=b;return a+(a>>31&mod);}
inline int mul(int a,int b){ll r=(ll)a*b;return r>=mod?r%mod:r;}
inline void Inc(int &a,int b){a+=b-mod;a+=a>>31&mod;}
inline void Dec(int &a,int b){a-=b;a+=a>>31&mod;}
inline void Mul(int &a,int b){a=mul(a,b);}
inline int sum(int l,int r){return (ll)(r-l+1)*(r+l)/2%mod;}

cs int N=1e5+7;

namespace SGT{
	struct node{int v1,v2,smul,sv2;};
	inline node operator+(cs node &a,cs node &b){
		return (node){add(a.v1,b.v1),add(a.v2,b.v2),
				add(a.smul,b.smul),add(a.sv2,b.sv2)};
	}
	cs int N=::N<<2|1;
	node t[N];int ad1[N],ad2[N];
#define lc u<<1
#define rc lc|1
	inline void ad_v1(int u,int l,int r,int v){
		Inc(ad1[u],v);
		Inc(t[u].smul,mul(v,t[u].v2));
		Inc(t[u].v1,mul(r-l+1,v));
	}
	inline void ad_v2(int u,int l,int r,int v){
		Inc(ad2[u],v);
		Inc(t[u].smul,mul(v,t[u].v1));
		Inc(t[u].v2,mul(r-l+1,v));
		Inc(t[u].sv2,mul(sum(l,r),v));
	}
	inline void pushdown(int u,int l,int r){
		int mid=l+r>>1;
		if(ad1[u]){ad_v1(lc,l,mid,ad1[u]);ad_v1(rc,mid+1,r,ad1[u]);ad1[u]=0;}
		if(ad2[u]){ad_v2(lc,l,mid,ad2[u]);ad_v2(rc,mid+1,r,ad2[u]);ad2[u]=0;}
	}
	inline void modify(int u,int l,int r,int ql,int qr,int v,int op){
		if(ql<=l&&r<=qr)return op?ad_v1(u,l,r,v):ad_v2(u,l,r,v);
		int mid=l+r>>1;pushdown(u,l,r);
		if(ql<=mid)modify(lc,l,mid,ql,qr,v,op);
		if(mid<qr)modify(rc,mid+1,r,ql,qr,v,op);
		t[u]=t[lc]+t[rc];
	}
	inline node query(int u,int l,int r,int ql,int qr){
		if(ql<=l&&r<=qr)return t[u];
		int mid=l+r>>1;pushdown(u,l,r);
		if(qr<=mid)return query(lc,l,mid,ql,qr);
		if(mid<ql)return query(rc,mid+1,r,ql,qr);
		return query(lc,l,mid,ql,qr)+query(rc,mid+1,r,ql,qr);
	}
}

int n,m;
int pre[N],nxt[N],las[N],a[N],b[N];
int stk_mx[N],tp_mx,stk_mn[N],tp_mn;

signed main(){
#ifdef zxyoi
	freopen("nut.in","r",stdin);
#endif
	n=gi();int ans=0;
	for(int re i=1;i<=n;++i)a[i]=b[i]=gi();
	std::sort(b+1,b+n+1);m=std::unique(b+1,b+n+1)-b-1;
	for(int re i=1;i<=n;++i)a[i]=std::lower_bound(b+1,b+m+1,a[i])-b;
	for(int re i=1;i<=n;++i)pre[i]=las[a[i]]+1,las[a[i]]=i;
	for(int re i=1;i<=m;++i)las[i]=n+1;
	for(int re i=n;i>=1;--i)nxt[i]=las[a[i]]-1,las[a[i]]=i;
	for(int re i=1,p=1;i<=n;++i){
		while(tp_mx&&pre[stk_mx[tp_mx]]<=pre[i])
		SGT::modify(1,1,n,stk_mx[tp_mx-1]+1,stk_mx[tp_mx],mod-pre[stk_mx[tp_mx]],1),--tp_mx;
		SGT::modify(1,1,n,stk_mx[tp_mx]+1,i,pre[i],1);
		while(tp_mn&&nxt[stk_mn[tp_mn]]>=nxt[i])
		SGT::modify(1,1,n,stk_mn[tp_mn-1]+1,stk_mn[tp_mn],mod-nxt[stk_mn[tp_mn]],0),--tp_mn;
		SGT::modify(1,1,n,stk_mn[tp_mn]+1,i,nxt[i],0);
		stk_mx[++tp_mx]=stk_mn[++tp_mn]=i;
		p=std::max(p,pre[i]);
		auto t=SGT::query(1,1,n,p,i);
		Dec(ans,t.smul);Inc(ans,t.sv2);
		Inc(ans,mul(i,dec(t.v1,sum(p,i))));
	}
	cout<<ans<<"\n";
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值