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想知道,每组游客会去多少个景点。
Input
第一行两个整数N,M,意义见题面。
接下来一行N个整数,第i个是a[i],意义见题面。
接下来M行,第i行两个整数Li,Ri,意义见题目。
Output
M行,第i行表示第i组游客去的景点个数。
Sample Input
6 4
3 1 7 4 5 2
1 5
2 5
2 6
4 6
Sample Output
3
3
4
3
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
题解
先考虑按照a的值构造一棵笛卡尔树,对于一个询问l,r答案就是他们的lca到他们这两条链中到l链的每一个父亲的左儿子个数以及到r那边的右儿子个数
为什么这样做是对的呢?事实上对答案有贡献的并不是那个树节点对应的序列中的位置,如果这个点在序列中的位置在[l,r]外,那么一定有另一个在[l,r]中的点可以满足题目的要求
那么我们可以tarjan求lca,单调栈构造笛卡尔树来O(n)解决这个问题
贴代码
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cmath>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
const int maxn=1000005;
int a[maxn],fi[2*maxn],next[2*maxn],dui[2*maxn],sc[2*maxn],st[maxn*2],hc[maxn*2];
int fa[maxn],da[maxn],son[maxn][3],zu[maxn],yo[maxn];
int go[maxn][4];
bool bz[maxn];
int i,j,k,l,n,m,x,y,ans,p,root;
bool b1;
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');
}
void add(int x,int y){
if (!fi[x]){
fi[x]=++l; dui[l]=y; sc[x]=l;
} else{
next[sc[x]]=++l; dui[l]=y; sc[x]=l;
}
hc[l]=i;
}
int getfather(int x){
if (fa[x]==x) return x; else fa[x]=getfather(fa[x]);
return fa[x];
}
void dfs(int x){
fa[x]=x;
bz[x]=true;
p=fi[x];
if (da[x]>0){
zu[x]=zu[da[x]]; yo[x]=yo[da[x]];
if (son[da[x]][1]==x) zu[x]++; else yo[x]++;
}
while (p){
if (bz[dui[p]]==true) go[hc[p]][3]=getfather(dui[p]);
p=next[p];
}
if (son[x][1]) dfs(son[x][1]);
if (son[x][2]) dfs(son[x][2]);
fa[x]=da[x];
}
int main(){
// freopen("t3.in","r",stdin);
freopen("trip.in","r",stdin);
freopen("trip.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n) a[i]=read();
fo(i,1,m)
{
go[i][1]=read(); go[i][2]=read();
add(go[i][1],go[i][2]);
add(go[i][2],go[i][1]);
}
l=0;
fo(i,1,n){
b1=false;
while (l>0 && a[i]>a[st[l]])
{
l--;
b1=true;
}
if (b1){
da[i]=da[st[l+1]];
da[st[l+1]]=da[i];
son[da[i]][2]=i;
son[i][1]=st[l+1];
da[st[l+1]]=i;
} else {
son[st[l]][2]=i;
da[i]=st[l];
}
st[++l]=i;
if (l==1) root=i;
}
dfs(root);
fo(i,1,m){
ans=-zu[go[i][3]]+zu[go[i][1]]-yo[go[i][3]]+yo[go[i][2]]+1;
write(ans);
}
return 0;
}