青春野狼不做姐控偶像的梦 - 线段树 - 扫描线 - 单调栈

题目大意:给你一个排列,多次询问,每次给你一个区间,问有多少子区间,数字取出来sort一遍是连续的一段。
题解:
考虑l=1,r=n咋做。
考虑一段合法,当且仅当max-min=r-l。
那么用个单调栈预处理每个数字在哪些[l,r]会成为最大/最小值,然后扫描线维护max-min+l的最小值,显然由于[r,r]是答案所以能取到最小值的位置都一定是答案。
考虑整个问题,就是每次在所有最小值的位置+1,区间求和。
这个可以类似segment tree beats的在下传标记的时候根据当前区间和儿子区间的最小值的打小关系讨论一下即可。

#include<bits/stdc++.h>
#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 ull unsigned lint
#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;
namespace INPUT_SPACE{
    const int BS=(1<<24)+5;char Buffer[BS],*HD,*TL;
    char gc() { if(HD==TL) TL=(HD=Buffer)+fread(Buffer,1,BS,stdin);return (HD==TL)?EOF:*HD++; }
    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;
    }
}using INPUT_SPACE::inn;
namespace OUTPUT_SPACE{
    char ss[10000000],tt[30];int ssl,ttl;
    inline int print(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';
    }
    inline int Flush() { return fwrite(ss+1,sizeof(char),ssl,stdout),ssl=0,0; }
}using OUTPUT_SPACE::print;using OUTPUT_SPACE::Flush;
const int N=130000,Q=N;
int L[N],R[N],s[N],p[N];
vector<pair<pii,int> > v[N];
vector<pii> q[N];lint ans[Q];
inline int getLR(int n,int t=0)
{
    for(int i=1;i<=n;s[++t]=i++)
        while(t&&p[s[t]]<p[i]) R[s[t--]]=i-1;
    while(t) R[s[t--]]=n;
    for(int i=n;i>=1;s[++t]=i--)
        while(t&&p[s[t]]<p[i]) L[s[t--]]=i+1;
    while(t) L[s[t--]]=1;
    rep(i,1,n) v[i].pb(mp(mp(L[i],i),p[i])),v[R[i]+1].pb(mp(mp(L[i],i),-p[i]));
    return 0;
}
struct segment{
    int l,r,mn,cnt,mnpt,anspt;
    lint ans;segment *ch[2];
}*rt;
inline int push_up(segment* &rt)
{
    segment *&lc=rt->ch[0],*&rc=rt->ch[1];
    rt->mn=min(lc->mn,rc->mn);
    if(lc->mn==rc->mn) rt->cnt=lc->cnt+rc->cnt;
    else if(lc->mn<rc->mn) rt->cnt=lc->cnt;
    else rt->cnt=rc->cnt;
    return rt->ans=lc->ans+rc->ans,0;
}
int build(segment* &rt,int l,int r)
{
    rt=new segment,rt->l=l,rt->r=r;
    rt->ans=rt->anspt=rt->mnpt=0,rt->cnt=1;
    int mid=(l+r)>>1;if(l==r) return rt->mn=l;
    build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r);
    return push_up(rt);
}
inline int update_mn(segment* &rt,int v) { return rt->mn+=v,rt->mnpt+=v,0; }
inline int update_ans(segment* &rt,int v) { return rt->ans+=(lint)v*rt->cnt,rt->anspt+=v,0; }
inline int push_down(segment* &rt)
{
    if(rt->mnpt) update_mn(rt->ch[0],rt->mnpt),update_mn(rt->ch[1],rt->mnpt),rt->mnpt=0;
    if(rt->anspt)
        (rt->ch[0]->mn==rt->mn?update_ans(rt->ch[0],rt->anspt):0),
        (rt->ch[1]->mn==rt->mn?update_ans(rt->ch[1],rt->anspt):0),
        rt->anspt=0;
    return 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_mn(rt,v);
    if(rt->mnpt||rt->anspt) 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);
}
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->ans;lint ans=0;
    if(rt->mnpt||rt->anspt) push_down(rt);
    if(s<=mid) ans+=query(rt->ch[0],s,t);
    if(mid<t) ans+=query(rt->ch[1],s,t);
    return ans;
}
int main()
{
    int n=inn();rep(i,1,n) p[i]=inn();
    int qc=inn(),l;rep(i,1,qc) l=inn(),q[inn()].pb(mp(l,i));
    getLR(n);rep(i,1,n) p[i]=-p[i];getLR(n);build(rt,1,n);
    rep(r,1,n)
    {
        Rep(i,v[r]) update(rt,v[r][i].fir.fir,v[r][i].fir.sec,v[r][i].sec);
        update_ans(rt,1);
        Rep(i,q[r]) ans[q[r][i].sec]=query(rt,q[r][i].fir,r);
    }
    rep(i,1,qc) print(ans[i]);return Flush(),0;
}


猜你喜欢

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