【题目描述】
毛毛虫经过及时的变形,最终逃过的一劫,离开了菜妈的菜园。 毛毛虫经过千山万水,历尽千辛万苦,最后来到了小小的绍兴一中的校园里。
爬啊爬,爬啊爬毛毛虫爬到了一颗小小的“毛景树”下面,发现树上长着他最爱吃的毛毛果~ “毛景树”上有N个节点和N-1条树枝,但节点上是没有毛毛果的,毛毛果都是长在树枝上的。但是这棵“毛景树”有着神奇的魔力,他能改变树枝上毛毛果的个数:
-
Change k w:将第k条树枝上毛毛果的个数改变为w个。
-
Cover u v w:将节点u与节点v之间的树枝上毛毛果的个数都改变为w个。
-
Add u v w:将节点u与节点v之间的树枝上毛毛果的个数都增加w个。 由于毛毛虫很贪,于是他会有如下询问:
-
Max u v:询问节点u与节点v之间树枝上毛毛果个数最多有多少个。
【输入格式】
第一行一个正整数N。
接下来N-1行,每行三个正整数Ui,Vi和Wi,第i+1行描述第i条树枝。表示第i条树枝连接节点Ui和节点Vi,树枝上有Wi个毛毛果。 接下来是操作和询问,以“Stop”结束。
【输出格式】
对于毛毛虫的每个询问操作,输出一个答案。
S a m p l e    I n p u t Sample\;Input SampleInput
4
1 2 8
1 3 7
3 4 9
Max 2 4
Cover 2 4 5
Add 1 4 10
Change 1 16
Max 2 4
Stop
S a m p l e    O u t p u t Sample\;Output SampleOutput
9
16
【题意分析】
很久之前就想水这道题了,由于畏惧码量一直没写~~
码量跟国集的那道旅游有的一拼。。。200+行(跟奆佬们的Toptree和RBT比起来少得多了,但对于我这种蒟蒻还是写了1h+)
思路就是边权树剖,维护一颗区间最大值的线段树,有两个懒标记lazyA[],lazyC[]
分别代表区间加懒标记、区间覆盖懒标记~~
p
u
s
h
d
o
w
n
pushdown
pushdown时,区间覆盖标记优先处理。
代码很多地方都是基本一样的,太无脑了。。。
真水
Code:
#pragma GCC optimize(2)
#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<cctype>
#include<cstring>
#include<vector>
#include<algorithm>
#define Read(a) a = read <int> ()
#define MAXN 200000
#define int long long
#define INF 1 << 30
using namespace std;
int tree[MAXN << 2],lazyA[MAXN << 2],lazyC[MAXN << 2],father[MAXN],son[MAXN];
int head[MAXN << 1],top[MAXN],id[MAXN],value[MAXN],rk[MAXN],depth[MAXN],size[MAXN];
int n,cnt,dfn,res,ans;
struct Front_Link_Star{
int from,to,next,v;
}edge[MAXN << 1];
//连边,记录从哪里来,到哪里去(这是为了边权化点权)
inline void connect (int u,int v,int w){
edge[++cnt].from = u;
edge[cnt].to = v;
edge[cnt].v = w;
edge[cnt].next = head[u];
head[u] = cnt;
}
template <typename T> inline T read (){
register int s = 0,w = 1;
register char ch = getchar ();
while (!isdigit (ch)){if (ch == '-')w = -1;ch = getchar ();}
while (isdigit (ch)){s = (s << 3) + (s << 1) + ch - '0';ch = getchar ();}
return s*w;
}
//判断权值应该给谁(深度大的那个)
inline void which (int &x){
x <<= 1;
(depth[edge[x].from] < depth[edge[x].to])
? x = edge[x].to : x = edge[x].from;
}
//向上推
inline void pushup (int now){
tree[now] = max (tree[now << 1],tree[now << 1 | 1]);
}
//标记下传,覆盖标记优先
inline void pushdown (int now){
if (lazyC[now] != -1){
tree[now << 1] = tree[now << 1 | 1] = lazyC[now];
lazyC[now << 1] = lazyC[now << 1 | 1] = lazyC[now];
lazyA[now << 1] = lazyA[now << 1 | 1] = 0;
lazyC[now] = -1;
}
if (lazyA[now]){
tree[now << 1] += lazyA[now];
tree[now << 1 | 1] += lazyA[now];
lazyA[now << 1] += lazyA[now];
lazyA[now << 1 | 1] += lazyA[now];
lazyA[now] = 0;
}
}
//建树
void build (int now,int tl,int tr){
lazyC[now] = -1; lazyA[now] = 0;
if (tl == tr){
tree[now] = value[rk[tl]];
return;
}
int mid = (tl + tr) >> 1;
build (now << 1,tl,mid);
build (now << 1 | 1,mid+1,tr);
pushup (now);
}
//update_Cover
void updateC (int now,int tl,int tr,int left,int right,int change){
if (right < tl || tr < left)return;
if (left <= tl && tr <= right){
tree[now] = lazyC[now] = change;
lazyA[now] = 0; return;
}
pushdown (now);
int mid = (tl + tr) >> 1;
updateC (now << 1,tl,mid,left,right,change);
updateC (now << 1 | 1,mid+1,tr,left,right,change);
pushup (now);
}
//update_Add
void updateA (int now,int tl,int tr,int left,int right,int change){
if (right < tl || tr < left)return;
if (left <= tl && tr <= right){
tree[now] += change;
lazyA[now] += change;
return;
}
pushdown (now);
int mid = (tl + tr) >> 1;
updateA (now << 1,tl,mid,left,right,change);
updateA (now << 1 | 1,mid+1,tr,left,right,change);
pushup (now);
}
void query (int now,int tl,int tr,int left,int right){
if (right < tl || tr < left)return;
if (left <= tl && tr <= right){
res = max (res,tree[now]);
return;
}
pushdown (now);
int mid = (tl + tr) >> 1;
query (now << 1,tl,mid,left,right);
query (now << 1 | 1,mid+1,tr,left,right);
}
//Modify_Range_Cover
inline void MRC (int x,int y,int z){
while (top[x] != top[y]){
if (depth[top[x]] < depth[top[y]])swap (x,y);
updateC (1,1,n,id[top[x]],id[x],z);
x = father[top[x]];
}
if (depth[x] > depth[y])swap (x,y);
updateC (1,1,n,id[x]+1,id[y],z);
}
//Modify_Range_Add
inline void MRA (int x,int y,int z){
while (top[x] != top[y]){
if (depth[top[x]] < depth[top[y]])swap (x,y);
updateA (1,1,n,id[top[x]],id[x],z);
x = father[top[x]];
}
if (depth[x] > depth[y])swap (x,y);
updateA (1,1,n,id[x]+1,id[y],z);
}
//Query_Range
inline void QR (int x,int y){
while (top[x] != top[y]){
if (depth[top[x]] < depth[top[y]])swap (x,y);
res = -INF;
query (1,1,n,id[top[x]],id[x]);
ans = max (ans,res);
x = father[top[x]];
}
if (depth[x] > depth[y])swap (x,y);
res = -INF;
query (1,1,n,id[x]+1,id[y]);
ans = max (ans,res);
}
void DFS1 (int now,int fa,int d){
father[now] = fa;
depth[now] = d;
size[now] = 1;
int maxson = -1;
for (register int i = head[now];i;i = edge[i].next){
int v = edge[i].to;
if (v == fa)continue;
DFS1 (v,now,d+1);
value[v] = edge[i].v;
size[now] += size[v];
if (size[v] > maxson){
maxson = size[v];
son[now] = v;
}
}
}
void DFS2 (int now,int top_heavy){
top[now] = top_heavy;
id[now] = ++dfn;
rk[dfn] = now;
if (!son[now])return;
DFS2 (son[now],top_heavy);
for (register int i = head[now];i;i = edge[i].next){
int v = edge[i].to;
if (v != father[now] && v != son[now])DFS2 (v,v);
}
}
signed main (){
Read (n);
for (register int i = 1;i < n;i++){
int x,y,z;
Read (x),Read (y),Read (z);
connect (x,y,z); connect (y,x,z);
}
DFS1 (1,0,1);
DFS2 (1,1);
build (1,1,n);
while ("11ai"){
char type[10];
scanf ("%s",type);
if (type[1] == 't')break; //stop
if (type[1] == 'a'){ //max
int x,y;
Read (x),Read (y);
ans = -INF; QR (x,y);
printf ("%lld\n",ans);
}
if (type[1] == 'o'){ //cover
int x,y,z;
Read (x),Read (y),Read (z);
MRC (x,y,z);
}
if (type[1] == 'd'){ //add
int x,y,z;
Read (x),Read (y),Read (z);
MRA (x,y,z);
}
if (type[1] == 'h'){ //change
int x,y;
Read (x),Read (y);
which (x);//应该修改哪里
updateC (1,1,n,id[x],id[x],y);
}
}
return 0;
}