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 } 
时间: 2024-10-28 19:05:18

poj3728The merchant树剖+线段树的相关文章

BZOJ4034 树上操作(树剖 线段树大模板)

BZOJ4034 long long 是大坑点 貌似long long 跟int 乘起来会搞事情?... A了这题线段树和树剖的基础OK 嘛 重点过掉的还是线段树区间更新的lazy tag吧 #include<cstdio> #include<cstring> #define N 100001 using namespace std; struct ed{ int nxt,to; }e[N*2]; int ne=0,head[N]; long long int w0[N]; str

POJ3417Network(LCA+树上查分||树剖+线段树)

Yixght is a manager of the company called SzqNetwork(SN). Now she's very worried because she has just received a bad news which denotes that DxtNetwork(DN), the SN's business rival, intents to attack the network of SN. More unfortunately, the origina

[GX/GZOI2019]旧词(树上差分+树剖+线段树)

考虑k=1的做法:这是一道原题,我还写过题解,其实挺水的,但当时我菜还是看题解的:https://www.cnblogs.com/hfctf0210/p/10187947.html.其实就是树上差分后值为1. 考虑k>1的做法:其实可以再次树上差分,给每个点i赋值v[i]=dep[i]k-dep[i-1]k,然后还是和原来一样开一棵线段树,记录一个val[rt]表示当前节点内区间v值的和,以及sum[rt]表示区间值.修改时打标记,只需要将sum[rt]+=v*val[rt],lazy[rt]+

bzoj 5210: 最大连通子块和【动态dp+树剖+线段树+堆】

参考:https://www.cnblogs.com/CQzhangyu/p/8632904.html 要开longlong的 首先看dp,设f[u]为必选u点的子树内最大联通块,p[u]为不一定选u的子树内最大联通块,转移很显然就是f[u]=max(Σf[v],0),p[u]=max(max(p[v]),f[u]) 然后看动态的部分,设g是不算重儿子的f,然后每条链上的真实f值要用一棵线段树维护g来得到,具体形式是f[u]=max(g[v]+f[hs[v]],0),是一个最长连续子序列的形式,

[BZOJ 1901] Dynamic Rankings 【树状数组套线段树 || 线段树套线段树】

题目链接:BZOJ - 1901 题目分析 树状数组套线段树或线段树套线段树都可以解决这道题. 第一层是区间,第二层是权值. 空间复杂度和时间复杂度均为 O(n log n). 代码 树状数组套线段树 #include <iostream> #include <cstdlib> #include <cstdio> #include <cmath> #include <algorithm> #include <cstring> usin

【vijos】1750 建房子(线段树套线段树+前缀和)

https://vijos.org/p/1750 是不是我想复杂了.... 自己yy了个二维线段树,然后愉快的敲打. 但是wa了两法.......sad 原因是在处理第二维的更新出现了个小问题,sad. void pushup1(int x) { for1(i, 1, mm<<2) mn[x][i]=min(mn[lc][i], mn[rc][i]); } 这里注意是mm*4...我该好好想想了..这是在dbg的时候找出来的问题.sad. 我觉得很奇怪,线段树的底层节点一共就mm个,那么整棵树

【bzoj4785】[Zjoi2017]树状数组 线段树套线段树

题目描述 漆黑的晚上,九条可怜躺在床上辗转反侧.难以入眠的她想起了若干年前她的一次悲惨的OI 比赛经历.那是一道基础的树状数组题.给出一个长度为 n 的数组 A,初始值都为 0,接下来进行 m 次操作,操作有两种: 1 x,表示将 Ax 变成 (Ax + 1) mod 2. 2 l r,表示询问 sigma(Ai) mod 2,L<=i<=r 尽管那个时候的可怜非常的 simple,但是她还是发现这题可以用树状数组做.当时非常young 的她写了如下的算法: 1: function Add(x

UVALive 7148 LRIP【树分治+线段树】

题意就是要求一棵树上的最长不下降序列,同时不下降序列的最小值与最大值不超过D. 做法是树分治+线段树,假设树根是x,y是其当前需要处理的子树,对于子树y,需要处理出两个数组MN,MX,MN[i]表示以x为第一个数字的不下降子序列中第i个数的最小值,MX[i]表示以x为第一个数字的不上升子序列中第i个数的最大值.如果当前子树有一个以x为首的不下降序列,那么我们就需要在之前处理的子树中找一条以x为首的满足约束条件不上升序列,可以用线段树来查询.同时每做完一颗子树的时候,用MN,MX对线段树进行更新.

区间树和线段树

注意:区间树和线段树不一样哦,线段树是一种特殊的区间树. 区间树: 区间树是在红黑树基础上进行扩展得到的支持以区间为元素的动态集合的操作,其中每个节点的关键值是区间的左端点.通过建立这种特定的结构,可是使区间的元素的查找和插入都可以在O(lgn)的时间内完成.相比于基础的红黑树数据结构,增加了一个max[x],即以x为根的子树中所有区间的断点的最大值.逻辑结构如下所示: 区间树具有和红黑树一样的性质,并且区间树的基础操作和红黑树的基础操作一样.(具体红黑树的操作,参见http://blog.cs