bzoj3999 [TJOI2015]旅游
Description
为了提高智商,ZJY准备去往一个新世界去旅游。这个世界的城市布局像一棵树。每两座城市之间只有一条路径可以互达。每座城市都有一种宝石,有一定的价格。ZJY为了赚取最高利益,她会选择从A城市买入再转手卖到B城市。由于ZJY买宝石时经常卖萌,因而凡是ZJY路过的城市,这座城市的宝石价格会上涨。让我们来算算ZJY旅游完之后能够赚取的最大利润。(如a城市宝石价格为v,则ZJY出售价格也为v)
Input
第一行输入一个正整数N,表示城市个数。
接下来一行输入N个正整数表示每座城市宝石的最初价格p,每个宝石的初始价格不超过100。
第三行开始连续输入N-1行,每行有两个数字x和y。表示x城市和y城市有一条路径。城市编号从1开始。
下一行输入一个整数Q,表示询问次数。
接下来Q行,每行输入三个正整数a,b,v,表示ZJY从a旅游到b,城市宝石上涨v。
1≤ N≤50000, 1≤Q ≤50000
Output
对于每次询问,输出ZJY可能获得的最大利润,如果亏本则输出0。
Sample Input
3
1 2 3
1 2
2 3
2
1 2 100
1 3 100
1 2 3
1 2
2 3
2
1 2 100
1 3 100
Sample Output
1
1
1
正解:树链剖分+线段树。
这题还是有点代码难度的,不过想清楚再写就很容易了。。
我们考虑维护4个东西,最小值,最大值,前缀最大减后缀最小,后缀最大减前缀最小,注意线段树的叶子结点的后两个标记必须为$0$,不然会出错。
如何合并标记?前两个标记很好合并,但是后两个似乎有点麻烦。其实很简单,后两个标记的合并可以分为两部分,一部分是两个儿子的标记取最值,还有一部分是左儿子的最大值减右儿子的最小值或左儿子的最小值减右儿子的最大值,两部分都取最大值就行了。
这题区间修改很$simple$,就是最小值和最大值加上修改的$w$就行了。
考虑如何查询。我们在跳链时会扣出$logn$个区间,那么答案由两部分组成。
一部分是一个区间以内的,这个部分就是这个区间的前缀最大减后缀最小或后缀最大减前缀最小。考虑如果这个区间的右端点更靠近$a$点,那么答案就是前者,否则是后者。
另一部分是不同区间之间的。那么首先我们要对这个区间按照从$a$到$b$经过的顺序排序。所以我们肯定要对每一个区间加上标记,具体的话看看我的代码就知道了。
然后我们直接$O(log^{2}n)$地暴力枚举两两区间。易知答案就是后一个区间的最大值减去前一个区间的最小值。
对于两个部分的答案,我们直接取最大值输出就行了。
1 //It is made by wfj_2048~ 2 #include <algorithm> 3 #include <iostream> 4 #include <complex> 5 #include <cstring> 6 #include <cstdlib> 7 #include <cstdio> 8 #include <vector> 9 #include <cmath> 10 #include <queue> 11 #include <stack> 12 #include <map> 13 #include <set> 14 #define inf (1<<30) 15 #define N (100010) 16 #define ls (x<<1) 17 #define rs (x<<1|1) 18 #define il inline 19 #define RG register 20 #define LL long long 21 #define File(s) freopen(s".in","r",stdin),freopen(s".out","w",stdout) 22 23 using namespace std; 24 25 struct edge{ LL nt,to; }g[2*N]; 26 struct data{ LL mn,mx,ll,rr; }; 27 struct node{ LL cnt,t; data res; }q[110]; 28 29 LL head[N],top[N],fa[N],son[N],p[N],sz[N],dep[N],tid[N],pos[N],n,num,cnt,Q; 30 LL lazy[4*N],mn[4*N],mx[4*N],ll[4*N],rr[4*N]; 31 32 il LL gi(){ 33 RG LL x=0,q=1; RG char ch=getchar(); 34 while ((ch<'0' || ch>'9') && ch!='-') ch=getchar(); 35 if (ch=='-') q=-1,ch=getchar(); 36 while (ch>='0' && ch<='9') x=x*10+ch-48,ch=getchar(); 37 return q*x; 38 } 39 40 il void insert(RG LL from,RG LL to){ 41 g[++num]=(edge){head[from],to},head[from]=num; return; 42 } 43 44 il LL cmpq(const node &a,const node &b){ 45 if (a.cnt!=b.cnt) return a.cnt<b.cnt; 46 if (a.cnt==1) return a.t<b.t; return a.t>b.t; 47 } 48 49 il void dfs1(RG LL x,RG LL p){ 50 fa[x]=p,dep[x]=dep[p]+1,sz[x]=1; RG LL v; 51 for (RG LL i=head[x];i;i=g[i].nt){ 52 v=g[i].to; if (v==p) continue; 53 dfs1(v,x); sz[x]+=sz[v]; 54 if (sz[son[x]]<=sz[v]) son[x]=v; 55 } 56 return; 57 } 58 59 il void dfs2(RG LL x,RG LL p,RG LL anc){ 60 top[x]=anc,tid[x]=++cnt,pos[cnt]=x; 61 if (son[x]) dfs2(son[x],x,anc); RG LL v; 62 for (RG LL i=head[x];i;i=g[i].nt){ 63 v=g[i].to; if (v==p || v==son[x]) continue; 64 dfs2(v,x,v); 65 } 66 return; 67 } 68 69 il void pushdown(RG LL x){ 70 mn[ls]+=lazy[x],mn[rs]+=lazy[x]; 71 mx[ls]+=lazy[x],mx[rs]+=lazy[x]; 72 lazy[ls]+=lazy[x],lazy[rs]+=lazy[x]; 73 lazy[x]=0; return; 74 } 75 76 il void merge(RG LL x,RG LL l,RG LL r){ 77 ll[x]=max(ll[ls],ll[rs]),ll[x]=max(ll[x],mx[ls]-mn[rs]); 78 rr[x]=max(rr[ls],rr[rs]),rr[x]=max(rr[x],mx[rs]-mn[ls]); 79 mn[x]=min(mn[ls],mn[rs]),mx[x]=max(mx[ls],mx[rs]); return; 80 } 81 82 il void build(RG LL x,RG LL l,RG LL r){ 83 if (l==r){ mn[x]=mx[x]=p[pos[l]]; return; } 84 RG LL mid=(l+r)>>1; build(ls,l,mid),build(rs,mid+1,r); 85 merge(x,l,r); return; 86 } 87 88 il void update(RG LL x,RG LL l,RG LL r,RG LL xl,RG LL xr,RG LL v){ 89 if (xl<=l && r<=xr){ mn[x]+=v,mx[x]+=v,lazy[x]+=v; return; } 90 if (lazy[x]) pushdown(x); RG LL mid=(l+r)>>1; 91 if (xr<=mid) update(ls,l,mid,xl,xr,v); 92 else if (xl>mid) update(rs,mid+1,r,xl,xr,v); 93 else update(ls,l,mid,xl,mid,v),update(rs,mid+1,r,mid+1,xr,v); 94 merge(x,l,r); return; 95 } 96 97 il data query(RG LL x,RG LL l,RG LL r,RG LL xl,RG LL xr){ 98 if (xl<=l && r<=xr) return (data){mn[x],mx[x],ll[x],rr[x]}; 99 if (lazy[x]) pushdown(x); RG LL mid=(l+r)>>1; 100 if (xr<=mid) return query(ls,l,mid,xl,xr); 101 else if (xl>mid) return query(rs,mid+1,r,xl,xr); 102 else{ 103 RG data res1=query(ls,l,mid,xl,mid); 104 RG data res2=query(rs,mid+1,r,mid+1,xr); 105 RG LL ll=max(res1.ll,res2.ll); ll=max(ll,res1.mx-res2.mn); 106 RG LL rr=max(res1.rr,res2.rr); rr=max(rr,res2.mx-res1.mn); 107 RG LL mn=min(res1.mn,res2.mn),mx=max(res1.mx,res2.mx); 108 return (data){mn,mx,ll,rr}; 109 } 110 } 111 112 il void change(RG LL u,RG LL v,RG LL w){ 113 while (top[u]!=top[v]){ 114 if (dep[top[u]]<dep[top[v]]) swap(u,v); 115 update(1,1,n,tid[top[u]],tid[u],w),u=fa[top[u]]; 116 } 117 if (dep[u]>dep[v]) swap(u,v); 118 update(1,1,n,tid[u],tid[v],w); return; 119 } 120 121 il LL Query(RG LL u,RG LL v){ 122 RG LL uu=0,vv=0,cntu=1,cntv=2,cnt=0,res=0; 123 while (top[u]!=top[v]){ 124 if (dep[top[u]]<dep[top[v]]) 125 swap(u,v),swap(uu,vv),swap(cntu,cntv); 126 q[++cnt]=(node){cntu,++uu,query(1,1,n,tid[top[u]],tid[u])}; 127 u=fa[top[u]]; 128 } 129 if (dep[u]>dep[v]) swap(u,v),swap(uu,vv),swap(cntu,cntv); 130 q[++cnt]=(node){cntv,++vv,query(1,1,n,tid[u],tid[v])}; 131 sort(q+1,q+cnt+1,cmpq); 132 for (RG LL i=1;i<=cnt;++i) 133 if (q[i].cnt==1) res=max(res,q[i].res.ll); 134 else res=max(res,q[i].res.rr); 135 for (RG LL i=1;i<cnt;++i) 136 for (RG LL j=i+1;j<=cnt;++j) 137 res=max(res,q[j].res.mx-q[i].res.mn); 138 return res; 139 } 140 141 il void work(){ 142 n=gi(); 143 for (RG LL i=1;i<=n;++i) p[i]=gi(); 144 for (RG LL i=1,u,v;i<n;++i) 145 u=gi(),v=gi(),insert(u,v),insert(v,u); 146 dfs1(1,0),dfs2(1,0,1),build(1,1,n),Q=gi(); 147 for (RG LL i=1,u,v,w;i<=Q;++i){ 148 u=gi(),v=gi(),w=gi(); 149 printf("%lld\n",Query(u,v)); 150 change(u,v,w); 151 } 152 return; 153 } 154 155 int main(){ 156 File("travel"); 157 work(); 158 return 0; 159 }