Trip

来源:互联网 发布:文本压缩算法 编辑:程序博客网 时间:2024/05/16 12:12

Trip

Time Limits: 1500 ms Memory Limits: 262144 KB

题目大意
给定一个数列a[1..n]|a[i]|109,数列中的数两两不同,给定m个询问,每个询问l,r,求存在多少个i[l,r]满足j[l,i)a[j]<a[i]或者j(j,r]a[j]<a[i]

输入
第一行两个整数n,m。
接下来一行n个整数,第i个是a[i]。
接下来m行,第i行两个整数Li,Ri。

输出
m行,第i行表示第i组游客去的景点个数。

样例
Input

6 43 1 7 4 5 21 52 52 64 6

Sample Output

3343

数据范围
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

提示
第一组游客选择路段的景点评估值序列为[3,1,7,4,5],其中3,7,5满足条件
第二组游客选择路段的景点评估值序列为[1,7,4,5],其中1,7,5满足条件
第三组游客选择路段的景点评估值序列为[1,7,4,5,2],其中3,7,5,2满足条件
第四组游客选择路段的景点评估值序列为[4,5,2],其中4,5,2满足条件
本题数据规模较大,请注意您的常数造成的影响。

解题思路

60%
考虑a[i]能对那些期间有贡献
我们找出两个位置j,k其中j<i<k其中p(j,i)a[p]<a[i],p(i,k)a[p]<a[i]那么i能产生贡献的区间[l,r]要满足j<l<i,r>ii<r<k,l<i
那么我们正着反着两次去扫,拿正着的说,反着的反之:
i从小到大扫,相应求出j,a[i]能对l(j,i]区间做贡献,那么就将(j,i]区间加1,用个数据结构维护
当i扫到i+1时,r=i的区间就会作废,那么直接求l上的值,计入答案就好了
由于这种方法,区间最大值会计算两次,最后-1就行
O(nlogn)
100%
建棵大根笛卡尔树:
也就是说树上的所有节点x满足x的下标大于左子树中所有节点的下标,小于所有右子树节点的下标,x的权值小于子树所有节点的权值
O(n)法:
假设当前子树代表区间[h,t],那么这棵子树的根节点x一定是区间[h,t]中权值最大的位置,它的左节点l是区间[h,x)中最大的比a[x]小的位置,右节点r同理
先找连向左节点的边:
因为一个点向左连边只可能连向它左边比它小的最大数位置,从1到n扫过去,维护一个栈,从栈底到栈顶数呈上升,扫到i时,将a[i]丢进栈,把小于a[i]的位置弹栈,左后弹栈的位置即为小于a[i]且最大的位置,i认它为左节点
右节点的反过来找

void maketree(){    a[0]=1000000001;sta[0]=0;top=0;    for(int i=1;i<=n;i++){        if(a[sta[top]]<a[i]){            while(a[sta[top]]<a[i])top--;            fa[sta[top+1]]=i;son[i][0]=sta[top+1];        }sta[++top]=i;    }top=0;    for(int i=n;i;i--){        if(a[sta[top]]<a[i]){            while(a[sta[top]]<a[i])top--;            fa[sta[top+1]]=i;son[i][1]=sta[top+1];        }sta[++top]=i;    }    for(root=1;fa[root]!=0;root=fa[root]);}

对于区间[l,r],最大值的位置就是l和r的lca,那么我们要求的是[l,r]中在路径(l,r)中的个数:1.lca 2.路径(l,lca)不包括lca为左节点 3.(r,lca)不包括lca为右节点
用个前缀和维护就好了
建树O(n)
tarjanlca O(nα(n))
询问 O(m)
总共是O(nα(n))
但是怕tarjanlca会爆栈,又懒得打人工栈,换用了链剖lca,复杂度远小于O(nlogn)
code:

#include<cstring>#include<cstdio>#define N 1001001using namespace std;int sta[N],a[N],n,m,fa[N],son[N][2],firx[N],firy[N],v[N],top,que[N],head,tail,rv[N],lv[N],root,Top[N],heavy[N],deep[N],siz[N];inline int read(){    int x=0,sig=1;char c;for(;(c=getchar())<'0' || c>'9';)if(c=='-')sig=-1;    for (;c>='0' && c<='9';c=getchar())x=(x<<1)+(x<<3)+c-48;return x*sig;}inline void write(int x){    int top=0;char ch[10];for(;x;x/=10)ch[++top]=x%10+48;    if(!top)ch[top=1]='0';while(top)putchar(ch[top--]);    putchar('\n');}inline void maketree(){    a[0]=1000000001;sta[0]=0;top=0;    for(int i=1;i<=n;i++){        if(a[sta[top]]<a[i]){            while(a[sta[top]]<a[i])top--;            fa[sta[top+1]]=i;son[i][0]=sta[top+1];lv[sta[top+1]]=1;        }sta[++top]=i;    }top=0;    for(int i=n;i;i--){        if(a[sta[top]]<a[i]){            while(a[sta[top]]<a[i])top--;            fa[sta[top+1]]=i;son[i][1]=sta[top+1];rv[sta[top+1]]=1;        }sta[++top]=i;    }    for(root=1;fa[root]!=0;root=fa[root]);rv[root]=1;}inline void makelink(){    for(head=0,siz[que[tail=1]=root]=1,deep[root]=1;head!=tail;){        head++;int now=que[head],l=son[now][0],r=son[now][1];        if(l)rv[l]+=rv[now],lv[l]+=lv[now],siz[que[++tail]=l]=1,deep[l]=deep[now]+1;        if(r)rv[r]+=rv[now],lv[r]+=lv[now],siz[que[++tail]=r]=1,deep[r]=deep[now]+1;    }    for(int i=tail;i;i--){        int x=que[i];        siz[x]+=siz[son[x][0]]+siz[son[x][1]];        if(son[x][0] && (!son[x][1] || siz[son[x][0]]>=siz[son[x][1]]))heavy[x]=son[x][0];        else if(son[x][1])heavy[x]=son[x][1];    }    for(head=0,Top[que[tail=1]=root]=root;head!=tail;){        head++;int now=que[head],l=son[now][0],r=son[now][1];        if(l && l==heavy[now])Top[que[++tail]=l]=Top[now];else if(l)Top[que[++tail]=l]=l;        if(r && r==heavy[now])Top[que[++tail]=r]=Top[now];else if(r)Top[que[++tail]=r]=r;    }}int main(){    freopen("trip.in","r",stdin);    freopen("trip.out","w",stdout);    n=read();m=read();    for(int i=1;i<=n;i++)a[i]=read();    maketree();makelink();    for(int i=1,x,y;i<=m;i++){        x=read(),y=read();        int lca;        for(int x_=x,y_=y;;){            if(Top[x_]==Top[y_]){if(deep[x_]>deep[y_])lca=y_;else lca=x_;break;}            if(deep[Top[x_]]>deep[Top[y_]])x_=fa[Top[x_]];else y_=fa[Top[y_]];        }        write(1+rv[y]-rv[lca]+lv[x]-lv[lca]);    }    fclose(stdin);fclose(stdout);    return 0;}