Description
多年之后,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想知道,每组游客会去多少个景点。
Data Constraint
30%:N,M≤5,000
60%:N,M≤100,000
100%:N,M≤1,000,000 0≤|a[i]|≤1,000,000,000 1≤Li≤Ri≤N
Solution
我们勾出一颗笛卡尔树,我们发现从l到lca的路径上唯有左子树到父亲是有贡献的,r到lca上唯有右子树到父亲是有贡献的。(因为l到lca的路径上若为右子树,说明l在父亲右边,不合法)
所以对于询问,直接用tarjan求一个lca即可。时间复杂度O(N)。
Code
#include<iostream>
#include<cmath>
#include<cstring>
#include<cstdio>
#include<algorithm>
using namespace std;
const int maxn=1e6+5;
struct code{
int x,y,lca;
}b[maxn];
int a[maxn],d[maxn],f[maxn][2],first[maxn],last[2*maxn],next[2*maxn],fa[maxn];
int id[maxn*2],bz[maxn],l[maxn],r[maxn];
int n,m,i,mx,ans,t,j,k,x,y,z,num;
char ch;
void lian(int x,int y,int z){
last[++num]=y;next[num]=first[x];first[x]=num;id[num]=i;
}
int getfa(int x){
return (fa[x]==x)?x:fa[x]=getfa(fa[x]);
}
void dg(int x,int y){
int t;
if (!x) return;
l[f[x][0]]=l[x]+1;l[f[x][1]]=l[x];
r[f[x][1]]=r[x]+1;r[f[x][0]]=r[x];
dg(f[x][0],x);dg(f[x][1],x);
for (t=first[x];t;t=next[t])
if (bz[last[t]]){
z=getfa(last[t]);
b[id[t]].lca=z;
}
bz[x]=1;
fa[x]=y;
}
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;
}
int main(){
freopen("trip.in","r",stdin);freopen("trip.out","w",stdout);
scanf("%d%d\n",&n,&m);
for (i=1;i<=n;i++){
a[i]=read();
while (a[d[d[0]]]<a[i] && d[0]) d[0]--;
f[i][0]=f[d[d[0]]][1];fa[i]=i;
f[d[d[0]]][1]=i;
d[++d[0]]=i;
}
scanf("\n");
for (i=1;i<=m;i++){
x=read();y=read();
b[i].x=x,b[i].y=y;
if (b[i].x==b[i].y) b[i].lca=x;
else lian(x,y,i),lian(y,x,i);
}
dg(d[1],0);
for (i=1;i<=m;i++){
t=l[b[i].x]-l[b[i].lca]+r[b[i].y]-r[b[i].lca]+1;
printf("%d\n",t);
}
}