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 } 

 

posted @ 2017-05-07 10:53  汪立超  阅读(155)  评论(0编辑  收藏