luogu P4755 Beautiful Pair - 啟發式合併 - 主席樹
阿新 • • 發佈:2018-11-01
題目大意:
給一個非負整數數列,問有多少子區間,端點權值乘積小於等於區間最大值。
(其實是啟發式分裂?
和這個題做法一模一樣,沒了。
// luogu-judger-enable-o2
#include<bits/stdc++.h>
#define gc getchar()
#define rep(i,a,b) for(int i=a;i<=b;i++)
#define Rep(i,v) rep(i,0,(int)v.size()-1)
#define lint long long
#define mod 998244353
#define N 100010
#define db long double
#define pb push_back
#define mp make_pair
#define fir first
#define sec second
#define debug(x) cerr<<#x<<"="<<x
#define sp <<" "
#define ln <<endl
using namespace std;
typedef pair<int,int> pii;
typedef set<int>::iterator sit;
inline int inn()
{
int x, ch;while((ch=gc)<'0'||ch>'9');
x=ch^'0';while((ch=gc)>='0'&&ch<='9')
x=(x<<1)+(x<<3)+(ch^'0');return x;
}
pii b[N];vector<int> v;int L[N],R[N],st[N],m,a[N],zo[N];set<int> s;
inline bool cmp(pii a,pii b) { return a.fir!=b.fir?a.fir>b.fir:a.sec< b.sec; }
inline int getid(int x) { return lower_bound(v.begin(),v.end(),x)-v.begin()+1; }
struct segment{
int s;segment *ch[2];
}*T[N];
int build(segment* &rt,int l,int r)
{
rt=new segment,rt->s=0;int mid=(l+r)>>1;if(l==r) return 0;
return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
}
int update(segment* &x,segment* &y,int p,int l,int r)
{
x=new segment,x->ch[0]=y->ch[0],x->ch[1]=y->ch[1];
x->s=y->s+1;if(l==r) return 0;int mid=(l+r)>>1;
if(p<=mid) update(x->ch[0],y->ch[0],p,l,mid);
else update(x->ch[1],y->ch[1],p,mid+1,r);return 0;
}
int query(segment* &x,segment* &y,int s,int t,int l,int r)
{
if(s<=l&&r<=t) return x->s-y->s;int mid=(l+r)>>1,ans=0;
if(s<=mid) ans+=query(x->ch[0],y->ch[0],s,t,l,mid);
if(mid<t) ans+=query(x->ch[1],y->ch[1],s,t,mid+1,r);
return ans;
}
inline int query(int L,int R,int s,int t)
{
if(L>R||s>t) return 0;
if(R-L<=40) { int ans=0;rep(i,L,R) ans+=(a[i]>=s&&a[i]<=t);return ans; }
int x=getid(s),y=getid(t);
if(v[y-1]>t) y--;if(x>y) return 0;
return query(T[R],T[L-1],x,y,1,m);
}
int main()
{
//freopen("data.in","r",stdin),freopen("std.out","w",stdout);
int n=inn();rep(i,1,n) a[i]=inn(),v.pb(a[i]);
sort(v.begin(),v.end());
v.erase(unique(v.begin(),v.end()),v.end());
m=(int)v.size(),build(T[0],1,m);
rep(i,1,n) update(T[i],T[i-1],getid(a[i]),1,m);
rep(i,1,n) L[i]=1,R[i]=n;lint ans=0;
for(int i=1,t=0;i<=n;st[++t]=i++)
while(t&&a[st[t]]<a[i]) R[st[t--]]=i-1;
for(int i=n,t=0;i>=1;st[++t]=i--)
while(t&&a[st[t]]<=a[i]) L[st[t--]]=i+1;
rep(i,1,n) zo[i]=zo[i-1]+(a[i]<=1);
s.insert(0),s.insert(n+1);
rep(i,1,n) b[i]=mp(a[i],i);
sort(b+1,b+n+1,cmp);
for(int i=1;i<=n;i++)
{
int x=b[i].sec,L,R;
sit it=s.lower_bound(x);
R=(*it)-1,it--,L=(*it)+1;
if(a[x]) ans+=zo[R]-zo[L-1];
else ans+=R-L+1;
int Llen=x-L,Rlen=R-x;
if(Llen<=Rlen) rep(j,L,x-1) ans+=(a[j]?query(x+1,R,0,a[x]/a[j]):Rlen);
else rep(j,x+1,R) ans+=(a[j]?query(L,x-1,0,a[x]/a[j]):Llen);
s.insert(x);
}
return !printf("%lld\n",ans);
}