标签:单调栈 freopen set isp ace getchar 需要 模板 std
考虑30分的可以拿个单调栈向左扫一遍向右扫一遍再将个数加起来再减去1即可。
这道题是要求我们判断这个景点的评估值在给定的子区间里是否有比它大值存在,如果一边没有大于它的存在,则它就是旅客会前往的景点。
既需要位置关系又需要大小关系,我们考虑大根笛卡尔树。
笛卡尔树是一种同时满足二叉搜索树和堆的性质的数据结构。
它的中序遍历的序列为原数组序列。
树中节点的值大于其左右子节点的值。
建树很简单, 用个单调栈O(n)即可建好。我们很容易发现一些性质:
1.对于一个询问L,R它的答案只会出现在笛卡尔树的路径上。
2.L,R的LCA中,从L到LCA路径上,有一个点是其父亲的左孩子答案就加一,R到LCA上,有一个点是其父亲的右孩子答案就加一。
我们知道笛卡尔树上一个点A是其父亲B的左孩子表明A在它父亲B的左边,且权值小于父亲B,对于L到LCA路径(也就是区间L-LCA)中而言这意味着A的左边没有比它大的点(如果有,那么A应该会在比它大的那个点C的右边),于是就对答案有1的贡献,虽然右边有比它大的点(父亲B);对于R到LCA路径(也就是区间LCA-R)中则相反。这就很好的符合题目的性质,我们就可以用笛卡尔树解决这道题了。
我们就可以用tarjan求出LCA,然后预处理下每个点到根节点的路径上有多少个点是其父亲的左孩子和右孩子,然后计算出答案即可。时间复杂度 O(NαN)
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #define N 3000002 5 using namespace std; 6 int n,m,t,zhan[N],len,num,ans[N],f[N],u,v,head[N],root,visit[N]; 7 struct data1{ 8 int l,r,p,v,lnum,rnum; 9 void init(){ 10 l=0,r=0,p=0,v=0,lnum=0,rnum=0; 11 } 12 }tree[N]; 13 struct data2{ 14 int next,to,sign; 15 }line[N]; 16 int read() 17 { 18 int x=0,sig=1; 19 char c; 20 for (c=getchar();c<‘0‘ || c>‘9‘;c=getchar()) if (c==‘-‘) sig=-1; 21 for (;c>=‘0‘ && c<=‘9‘;c=getchar()) x=x*10+c-48; 22 return x*sig; 23 } 24 void write(int x) 25 { 26 if (!x) putchar(‘0‘);else 27 { 28 char s[10]; 29 int i,j=0; 30 for (;x>0;x/=10) s[j++]=x%10; 31 for (i=j-1;i>=0;i--) putchar(s[i]+48); 32 } 33 putchar(‘\n‘); 34 } 35 void add(int u,int v){ 36 num++; 37 line[num].next=head[u]; 38 line[num].to=v; 39 line[num].sign=num; 40 head[u]=num; 41 num++; 42 line[num].next=head[v]; 43 line[num].to=u; 44 line[num].sign=num; 45 head[v]=num; 46 } 47 int build(){ //建笛卡尔树 48 len=1; 49 zhan[1]=1; 50 for (int i=2;i<=n;i++){ 51 while ((len>0)&&(tree[zhan[len]].v<tree[i].v)) len--; 52 if (len){ 53 tree[i].p=zhan[len]; 54 tree[tree[zhan[len]].r].p=i; 55 tree[i].l=tree[zhan[len]].r; 56 tree[zhan[len]].r=i; 57 } 58 else { 59 tree[zhan[1]].p=i; 60 tree[i].l=zhan[1]; 61 } 62 zhan[++len]=i; 63 } 64 return zhan[1]; 65 } 66 int find(int x){ 67 if (f[x]==x) return x; 68 f[x]=find(f[x]); 69 return f[x]; 70 } 71 void tarjan(int x,int ln,int rn){ //Tarjan求LCA 72 f[x]=x; 73 visit[x]=1; 74 tree[x].lnum=ln; 75 tree[x].rnum=rn; 76 if (tree[x].l) { 77 tarjan(tree[x].l,ln+1,rn); 78 f[tree[x].l]=x; 79 } 80 if (tree[x].r) { 81 tarjan(tree[x].r,ln,rn+1); 82 f[tree[x].r]=x; 83 } 84 int v=0,e=0; 85 for (int i=head[x];i!=0;i=line[i].next){ 86 v=line[i].to; 87 if (visit[v]){e=find(v); 88 if (line[i].sign&1) ans[(line[i].sign+1)/2]=tree[x].lnum-tree[e].lnum+tree[v].rnum-tree[e].rnum+1; 89 else ans[line[i].sign/2]=tree[v].lnum-tree[e].lnum+tree[x].rnum-tree[e].rnum+1; 90 } 91 } 92 } 93 int main(){ 94 freopen("trip.in","r",stdin); 95 freopen("trip.out","w",stdout); 96 memset(visit,0,sizeof(visit)); 97 n=read(); 98 m=read(); 99 for (int i=1;i<=n;i++){ 100 tree[i].init(); 101 tree[i].v=read(); 102 } 103 root=build(); 104 num=0; 105 for (int i=1;i<=m;i++){ 106 u=read(); 107 v=read(); 108 add(u,v); 109 } 110 tarjan(root,0,0); 111 for (int i=1;i<=m;i++) 112 write(ans[i]); 113 return 0; 114 }
联想很重要
标签:单调栈 freopen set isp ace getchar 需要 模板 std
原文地址:http://www.cnblogs.com/Lanly/p/7309433.html