poj3728The merchant树剖+线段树
Posted 汪立超
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了poj3728The merchant树剖+线段树相关的知识,希望对你有一定的参考价值。
如果直接在一条直线上,那么就建线段树
考虑每一个区间维护最小值和最大值和答案,就符合了合并的条件,一个log轻松做
那么在树上只要套一个树剖就搞定了,多一个log也不是问题
注意考虑在树上的话每一条链都有可能是正着被用和反着被用,所以存两个答案
所以维护信息只需要一个merge和一个reverse
代码如下:
1 #include <cstdio> 2 #include <iostream> 3 #define mid (l+r>>1) 4 using namespace std; 5 struct node 6 { 7 int ma,mi,ans,rev_ans; 8 node() 9 { 10 ma=0;mi=2000000000;ans=0;rev_ans=0; 11 } 12 node(int a,int b,int c,int d) 13 { 14 ma=a;mi=b;ans=c;rev_ans=d; 15 } 16 void rever() 17 { 18 swap(ans,rev_ans); 19 } 20 } tr[400001]; 21 int N,TIME,n,m,p,q; 22 int to[100001],nex[100001],fir[100001],w[100001],pos[100001],loc[100001]; 23 int fa[100001],size[100001],dep[100001],top[100001]; 24 node merge(node a,node b) 25 { 26 return node(max(a.ma,b.ma),min(a.mi,b.mi),max(b.ma-a.mi,max(a.ans,b.ans)),max(a.ma-b.mi,max(a.rev_ans,b.rev_ans))); 27 } 28 void add(int p,int q) 29 { 30 to[++N]=q;nex[N]=fir[p];fir[p]=N; 31 to[++N]=p;nex[N]=fir[q];fir[q]=N; 32 } 33 int build(int now,int fat) 34 { 35 fa[now]=fat;size[now]=1;dep[now]=dep[fat]+1; 36 for(int i=fir[now];i;i=nex[i]) 37 if(to[i]!=fat) 38 size[now]+=build(to[i],now); 39 return size[now]; 40 } 41 void pou(int now,int tp) 42 { 43 top[now]=tp;loc[++TIME]=now; 44 pos[now]=TIME; 45 int best=0; 46 for(int i=fir[now];i;i=nex[i]) 47 if(to[i]!=fa[now]) 48 best=best?((size[best]<size[to[i]])?to[i]:best):to[i]; 49 if(best) 50 pou(best,tp); 51 for(int i=fir[now];i;i=nex[i]) 52 if(to[i]!=fa[now] && to[i]!=best) 53 pou(to[i],to[i]); 54 } 55 void work(int now,int l,int r) 56 { 57 if(l==r) 58 { 59 tr[now]=node(w[loc[l]],w[loc[l]],0,0); 60 return; 61 } 62 work(now<<1,l,mid); 63 work(now<<1|1,mid+1,r); 64 tr[now]=merge(tr[now<<1],tr[now<<1|1]); 65 } 66 node que(int now,int l,int r,int x,int y) 67 { 68 if(l==x && r==y) 69 return tr[now]; 70 node ret=node(); 71 if(x<=mid) 72 ret=que(now<<1,l,mid,x,min(y,mid)); 73 if(y>mid) 74 ret=merge(ret,que(now<<1|1,mid+1,r,max(mid+1,x),y)); 75 return ret; 76 } 77 int main() 78 { 79 scanf("%d",&n); 80 for(int i=1;i<=n;i++) 81 scanf("%d",&w[i]); 82 for(int i=1;i<n;i++) 83 scanf("%d%d",&p,&q),add(p,q); 84 build(1,0); 85 pou(1,1); 86 work(1,1,n); 87 scanf("%d",&m); 88 for(int i=1;i<=m;i++) 89 { 90 scanf("%d%d",&p,&q); 91 node P=node(),Q=node(); 92 while(top[p]!=top[q]) 93 { 94 if(dep[top[p]]<dep[top[q]]) 95 {//work on q 96 Q=merge(que(1,1,n,pos[top[q]],pos[q]),Q); 97 q=fa[top[q]]; 98 } 99 else 100 {//work on p 101 node now=que(1,1,n,pos[top[p]],pos[p]); 102 now.rever(); 103 P=merge(P,now); 104 p=fa[top[p]]; 105 } 106 } 107 if(dep[p]<dep[q]) 108 P=merge(P,que(1,1,n,pos[p],pos[q])); 109 else 110 { 111 node now=que(1,1,n,pos[q],pos[p]); 112 now.rever(); 113 P=merge(P,now); 114 } 115 P=merge(P,Q); 116 printf("%d\n",P.ans); 117 } 118 return 0; 119 }
以上是关于poj3728The merchant树剖+线段树的主要内容,如果未能解决你的问题,请参考以下文章
[最近公共祖先] POJ 3728 The merchant
POJ3728The merchant (倍增)(LCA)(DP)(经典)(||并查集压缩路径?)