洛谷$P4755 Beautiful Pair$ 最大值分治

正解:最大值分治

解题报告:

传送门$QwQ$

昂考虑如果已经钦定了点$x$是这个$max$了,然后现在要求有多少对$[l,r]$满足$a_x=maxleft{a_i ight},iin[l,r]$,且$a_lcdot a_rleq a_x$

现在枚举$l$,发现$r$就有一个范围了,就$a_rleq frac{a_x}{a_l}$,这个就可以用主席树维护下就成嘛$QwQ$(我开始想用树状数组的,,,然后想了下发现因为是分治所以每次树状数组都要重建复杂度是错的$kk$,所以还是去用主席树趴$QwQ$

所以就基本上能得出这题的基本思路了?首先找到区间最大值$x$,先分别求出$x$两侧的答案,然后统计跨过$x$的贡献.考虑枚举$l$,然后对于$r$就直接树状数组搞下就行.但是发现如果$l$中的点太多也不可,所以考虑枚举$size$较小的那一边.

这个的复杂度和启发式合并的复杂度是一样的,就$O(nlogn)$,然后加上树状数组的复杂度,总复杂度就两个$log$的

$over$?

 

#include<bits/stdc++.h>
using namespace std;
#define il inline
#define gc getchar()
#define mp make_pair
#define int long long
#define ri register int
#define rc register char
#define rb register bool
#define rp(i,x,y) for(ri i=x;i<=y;++i)
#define my(i,x,y) for(ri i=x;i>=y;--i)
#define lb(x) lower_bound(b+1,b+1+num,x)-b
#define ub(x) upper_bound(b+1,b+1+num,x)-b

const int N=1e5+10;
int n,a[N],b[N],st[20][N],num,rt[N],nod_cnt,lg[N];
struct node{int num,ls,rs;}tr[N*64];

il int read()
{
    rc ch=gc;ri x=0;rb y=1;
    while(ch!='-' && (ch>'9' || ch<'0'))ch=gc;
    if(ch=='-')ch=gc,y=0;
    while(ch>='0' && ch<='9')x=(x<<1)+(x<<3)+(ch^'0'),ch=gc;
    return y?x:-x;
}
il int cmp(ri gd,ri gs){return a[gd]>=a[gs]?gd:gs;}
il void pre()
{
    lg[0]=-1;rp(i,1,n)st[0][i]=i,lg[i]=lg[i>>1]+1;
    rp(i,1,lg[n])
        rp(j,1,n-(1<<i)+1)st[i][j]=cmp(st[i-1][j],st[i-1][j+(1<<(i-1))]);
}
il int ask(ri l,ri r){ri len=lg[r-l+1];return cmp(st[len][l],st[len][r-(1<<len)+1]);}
int modify(ri nw,ri l,ri r,ri to)
{
    ri x=++nod_cnt;tr[x]=tr[nw];++tr[x].num;if(l==r)return x;
    ri mid=(l+r)>>1;to<=mid?tr[x].ls=modify(tr[nw].ls,l,mid,to):tr[x].rs=modify(tr[nw].rs,mid+1,r,to);
    return x;
}
int query(ri nw,ri l,ri r,ri to)
{
    if(r<=to)return tr[nw].num;
    ri mid=(l+r)>>1,ret=query(tr[nw].ls,l,mid,to);
    if(mid<to)ret+=query(tr[nw].rs,mid+1,r,to);
    return ret;
}
int solv(ri l,ri r)
{
    if(l>r)return 0;
    if(l==r)return b[a[l]]==1;
    ri mid=ask(l,r),sum=0;sum+=solv(l,mid-1);sum+=solv(mid+1,r);//printf("l=%d r=%d sum=%d mid=%d solv(%d,%d),solv(%d,%d)
",l,r,sum,mid,l,mid-1,mid+1,r);
    ri tl=l,tr=mid,askl=mid,askr=r;if(mid-l+1>r-mid)swap(tl,askl),swap(tr,askr);
    //printf("tl=%d tr=%d askl=%d askr=%d
",tl,tr,askl,askr);
    rp(i,tl,tr)
    {
        ri lim=ub(b[a[mid]]/b[a[i]])-1;if(lim)sum+=query(rt[askr],1,num,lim)-query(rt[askl-1],1,num,lim);
    }
    //printf("l=%d r=%d sum=%d
",l,r,sum);
    return sum;
}

signed main()
{
    //freopen("4755.in","r",stdin);freopen("4755.out","w",stdout);
    n=read();rp(i,1,n)a[i]=b[i]=read();sort(b+1,b+1+n);num=unique(b+1,b+1+n)-b-1;
    rp(i,1,n)a[i]=lb(a[i]),rt[i]=modify(rt[i-1],1,num,a[i]);
    pre();printf("%lld
",solv(1,n));
    return 0;
}
View Code

 

原文地址:https://www.cnblogs.com/lqsukida/p/11494906.html