[HNOI2017] bzoj 4826 影魔 - 线段树 - 扫描线 - 单调栈

题目大意:给一个排列p,多次询问一个区间[l,r]的中有多少子区间[i,j]满足:
m x ( i + 1 , j 1 ) m i n ( p [ i ] , p [ j ] ) mx(i+1,j-1)\le min(p[i],p[j]) (记做cnt1),或者 m i n ( p [ i ] , p [ j ] ) < m x ( i + 1 , j 1 ) < m a x ( p [ i ] , p [ j ] ) min(p[i],p[j])<mx(i+1,j-1)<max(p[i],p[j]) (记做cnt2),并输出 c n t 1 q 1 + c n t 2 q 2 cnt1*q1+cnt2*q2 。其中mx为区间p的最大值。
题解:
考虑对mx统计。设a[c]=mx(i+1,j-1)。记L[c]为c左第一个比c大的数字的位置。
若a[c]对cnt1有贡献,则i=L[c],j=R[c],此时若询问l,r包含i,j,则对cnt1有1的贡献。同里,当选i=L[c],c+1<=j<=R[c]的时候或者同理,会对答案有cnt2的贡献。
然后做扫描线即可,正反做两边线段树维护一下。

#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 N 200010
#define db 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;
}
struct segment{
    int l,r;lint s,pt;
    segment *ch[2];
}*rt;int a[N],L[N],R[N],s[N],ql[N],qr[N];
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->l=l,rt->r=r,rt->s=rt->pt=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);
}
inline int update_tags(segment* &rt,lint v) { return rt->s+=(rt->r-rt->l+1)*v,rt->pt+=v,0; }
inline int push_up(segment* &rt) { return rt->s=rt->ch[0]->s+rt->ch[1]->s,0; }
inline int push_down(segment* &rt) { return update_tags(rt->ch[0],rt->pt),update_tags(rt->ch[1],rt->pt),rt->pt=0,0; }
int update(segment* &rt,int s,int t,int v)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(s<=l&&r<=t) return update_tags(rt,v);
    if(rt->pt) push_down(rt);
    if(s<=mid) update(rt->ch[0],s,t,v);
    if(mid<t) update(rt->ch[1],s,t,v);
    return push_up(rt),0;
}
lint query(segment* &rt,int s,int t)
{
    int l=rt->l,r=rt->r,mid=(l+r)>>1;
    if(s<=l&&r<=t) return rt->s;
    if(rt->pt) push_down(rt);lint ans=0;
    if(s<=mid) ans+=query(rt->ch[0],s,t);
    if(mid<t) ans+=query(rt->ch[1],s,t);
    return ans;
}
vector<pii> q1[N],q2[N];lint ans[N];
vector< pair<pii,int> > v1[N],v2[N];
char ss[N*22],tt[25];int ssl,ttl;
inline int show(lint x)
{
    if(!x) ss[++ssl]='0';
    for(ttl=0;x;x/=10) tt[++ttl]=char(x%10+'0');
    for(;ttl;ttl--) ss[++ssl]=tt[ttl];
    return ss[++ssl]='\n';
}
int main()
{
    int n=inn(),q=inn(),p1=inn(),p2=inn();
    rep(i,1,n) a[i]=inn();int t=0,x,y;
    rep(i,1,q) x=ql[i]=inn(),y=qr[i]=inn(),q1[y].pb(mp(x,i)),q2[x].pb(mp(y,i));
    for(int i=1;i<=n;s[++t]=i++) while(t&&a[s[t]]<a[i]) R[s[t--]]=i;
    while(t) R[s[t--]]=n+1;
    for(int i=n;i>=1;s[++t]=i--) while(t&&a[s[t]]<a[i]) L[s[t--]]=i;
    while(t) L[s[t--]]=0;
    rep(c,1,n)
    {
        if(L[c]>=1&&R[c]<=n) v1[R[c]].pb(mp(mp(L[c],L[c]),p1));
        if(R[c]<=n&&c-1>=L[c]+1) v1[R[c]].pb(mp(mp(L[c]+1,c-1),p2));
        if(L[c]>=1&&c+1<=R[c]-1) v2[L[c]].pb(mp(mp(c+1,R[c]-1),p2));
    }
    build(rt,1,n);
    rep(i,1,n)
    {
        Rep(j,v1[i]) update(rt,v1[i][j].fir.fir,v1[i][j].fir.sec,v1[i][j].sec);
        Rep(j,q1[i]) ans[q1[i][j].sec]+=query(rt,q1[i][j].fir,i);
    }
    build(rt,1,n);
    for(int i=n;i;i--)
    {
        Rep(j,v2[i]) update(rt,v2[i][j].fir.fir,v2[i][j].fir.sec,v2[i][j].sec);
        Rep(j,q2[i]) ans[q2[i][j].sec]+=query(rt,i,q2[i][j].fir);
    }
    rep(i,1,q) show(ans[i]+(qr[i]-ql[i])*p1);
    return fwrite(ss+1,sizeof(char),ssl,stdout),0;
}

猜你喜欢

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