【JZOJ5246】【NOIP2017模拟8.8A组】Trip

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);
    }
}
发布了257 篇原创文章 · 获赞 451 · 访问量 10万+

猜你喜欢

转载自blog.csdn.net/crybymyself/article/details/76975046