luogu P4755 Beautiful Pair - 启发式合并 - 主席树

题目大意:
给一个非负整数数列,问有多少子区间,端点权值乘积小于等于区间最大值。
(其实是启发式分裂?
这个题做法一模一样,没了。

// 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);
}

猜你喜欢

转载自blog.csdn.net/Mys_C_K/article/details/83504038