题目大意
多年之后,worldwideD厌倦竞争,隐居山林。
他的家乡开始发展起了旅游业,在一条很长的主干道上,有N个旅游景点,按顺序编号为1到N。根据游客们网上的评分,第i个景点有一个评估值a[i],为了区分开不同的景点,评估值是两两不同的。
今天有M组游客前来旅游,第i组游客选择遍历景点Li到景点Ri这一段路。他们搜到Li到Ri的所有评估值,如果对于景点j(Li≤j≤Ri),不存在景点x(Li≤x<j)满足a[x]>a[j]或不存在景点y(j<y≤Ri)满足a[y]>a[j],那么他们会进入景点j。
现在worldwideD想知道,每组游客会去多少个景点。
解题思路
构出笛卡尔树发现答案即l到lca是父亲左儿子点的个数加上r到lca是父亲右儿子点的个数。考虑lca左边的点,左边一定不能有比它大的数,而一个点是父亲左儿子,要么就是左边没有比他大的数,要么就是在l的左边。
点的个数可以一遍dfs算出根到当前点的答案,求lca可以离线用tarjan-lca求出。
code
using namespace std;
int const mn=1e6+9;LL inf=1e18+7;
int n,m,lg2,gra,begin[mn],to[mn],pos[mn],next[mn],a[mn],f[mn],g[mn],
son[mn][2],fa[mn],par[mn],ans[mn],st[mn],dep[mn],ccc;
void insert(int r,int l,int p){
to[++gra]=l;
pos[gra]=p;
next[gra]=begin[r];
begin[r]=gra;
}
int get(int x){
if(!par[x])return x;
return par[x]=get(par[x]);
}
void dfs(int p){
int i=0;
if(son[p][i]){
f[son[p][i]]=f[p]+(i==0);
g[son[p][i]]=g[p]+(i==1);
fa[son[p][i]]=p;
dfs(son[p][i]);
par[son[p][i]]=p;
}
fr(i,p){
int lca=fa[get(to[i])];
ans[pos[i]]=f[to[i]]-f[lca]+g[p]-g[lca];
}
i=1;
if(son[p][i]){
f[son[p][i]]=f[p]+(i==0);
g[son[p][i]]=g[p]+(i==1);
fa[son[p][i]]=p;
dfs(son[p][i]);
par[son[p][i]]=p;
}
}
int read(){
int x=0,sig=1;
char c;
for (c=getchar();c<'0' || c>'9';c=getchar()) if (c=='-') sig=-1;
for (;c>='0' && c<='9';c=getchar()) x=x*10+c-48;
return x*sig;
}
void write(int x){
if (!x) putchar('0');else{
char s[10];
int i,j=0;
for (;x>0;x/=10) s[j++]=x%10;
for (i=j-1;i>=0;i--) putchar(s[i]+48);
}
putchar('\n');
}
int main(){
//freopen("trip.in","r",stdin);
//freopen("trip.out","w",stdout);
freopen("d.in","r",stdin);
freopen("d.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n)a[i]=read();
fo(i,1,n){
int tmp=st[0];
while(st[0]&&(a[st[st[0]]]<a[i]))st[0]--;
if(tmp!=st[0]){
fo(j,st[0]+1,tmp-1)son[st[j]][1]=st[j+1];
son[i][0]=st[st[0]+1];
}
st[++st[0]]=i;
}
fo(i,1,st[0]-1)son[st[i]][1]=st[i+1];
f[st[1]]=1;
fo(i,1,m){
int l=read(),r=read();
insert(r,l,i);
}
dfs(st[1]);
fo(i,1,m)write(ans[i]);
return 0;
}