青春野狼不做姐控偶像的夢 - 線段樹 - 掃描線 - 單調棧
阿新 • • 發佈:2018-12-30
題目大意:給你一個排列,多次詢問,每次給你一個區間,問有多少子區間,數字取出來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;
}