题意:维修数列的树上路径版,操作:将一段路径上的点权设为同一个值,求一段路径上的最大字段和。
坑了我好大半天!!!copy维修数列代码的都会被坑惨!!
坑点一:题目中说的最大字段和可以为空。这尼玛哪门子最大字段和还可以为空。。
坑点二:维修数列当中有一个经典的优化:当一个节点有makesame标记,下传的时候可以取消掉reverse标记。原因很明显,当你把一段区间设为同一个值的话,之前的反转操作很显然没意义了。这道题是LCT,节点是始终绑定了的,reverse就是对树的路径的反转,这是一定不能省掉的,即使这段路径有了相同的值,他们内部的关系是一定要维护好的,而维修数列当中节点并没有数组当中固定的位置,数列的第K位是根据size来临时确定的,所以没有关系。
网上写LCT过这道题的人都没换根,佩服他们的勇气。
#include<stdio.h>
#include<cstring>
#include<algorithm>
const int MAXN = 100010;
using namespace std;
int N, Q;
int w[MAXN];
void crash() { crash(); }
struct Node {
int sz, lmx, rmx, mx, w, sum;
bool rev, sam;
Node*fa, *ch[2], *pfa;
Node () ;
} nil, *NIL = &nil;
Node::Node() {
fa = ch[0] = ch[1] = pfa = NIL;
sz = 0;
rev = sam = 0;
w = sum = 0;
lmx = rmx = mx = 0;
}
struct LCT {
#define lch(x) x->ch[0]
#define rch(x) x->ch[1]
Node nd[MAXN];
void uprev(Node*x)
{
if (x==NIL) return;
swap(lch(x), rch(x));
swap(x->lmx, x->rmx);
x->rev ^= 1;
}
void upsam(Node*x, int v)
{
if (x==NIL) return;
x->w = v;
x->sum = v * x->sz;
x->mx = x->lmx = x->rmx = max(x->sum, 0);
x->sam = 1;
}
void pushup(Node*x)
{
Node*L = lch(x), *R = rch(x);
x->sz = L->sz + R->sz + 1;
x->sum = L->sum + R->sum + x->w;
x->lmx = max(L->lmx, L->sum+x->w+R->lmx);
x->rmx = max(R->rmx, R->sum+x->w+L->rmx);
x->mx = max(L->rmx + x->w + R->lmx, max(L->mx, R->mx));
}
void pushdown(Node*x)
{
if (x==NIL) return;
if (x->sam)
{
x->sam = 0;
upsam(lch(x), x->w);
upsam(rch(x), x->w);
}
if (x->rev)
{
x->rev = 0;
uprev(lch(x));
uprev(rch(x));
}
}
void rotate(Node*x)
{
Node *y = x->fa;
pushdown(y);
pushdown(x);
int d = (x==lch(y));
y->ch[!d] = x->ch[d];
if (x->ch[d] != NIL) x->ch[d]->fa = y;
x->fa = y->fa;
if (y->fa != NIL)
y->fa->ch[ y->fa->ch[1]==y ] = x;
x->pfa = y->pfa;
y->pfa = NIL;
x->ch[d] = y;
y->fa = x;
pushup(y);
}
void splay(Node*x, Node*to = NIL)
{
pushdown(x);
for (Node *y, *z; x->fa != to; rotate(x))
{
y = x->fa; z = y->fa;
if (z != NIL) rotate((y==lch(z))^(x==lch(y)) ? x : y);
}
pushup(x);
}
void access(Node*x)
{
Node*y = NIL;
for (; x != NIL; x = x->pfa)
{
splay(x);
if (rch(x) != NIL)
rch(x)->pfa = x, rch(x)->fa = NIL;
x->ch[1] = y;
y->fa = x; y->pfa = NIL;
pushup(y = x);
}
}
void makeroot(Node*x) {
access(x), splay(x), uprev(x);
}
int quary(int u, int v)
{
Node*x = nd+u, *y = nd+v;
makeroot(x);
access(y), splay(y);
pushdown(y);
if (u == v) return max(y->w, 0);
return max(lch(y)->mx, lch(y)->rmx + y->w);
}
void makesame(int u, int v, int w)
{
Node*x = nd+u, *y = nd+v;
makeroot(x);
access(y), splay(y);
pushdown(y), pushup(y);
if (lch(y)!=NIL)
{
pushdown(lch(y)), pushup(lch(y));
upsam(y->ch[0], w);
pushdown(y->ch[0]);
}
y->w = w;
pushup(y);
}
} lct;
struct Ed {
int to; Ed*nxt;
}*adj[MAXN], Edges[MAXN*2], *ecnt=Edges;
void adde(int a, int b)
{
(++ecnt)->to = b;
ecnt->nxt = adj[a];
adj[a] = ecnt;
}
void DFS(int u, int fa)
{
Node&t = lct.nd[u];
if (~fa) t.pfa = lct.nd + fa;
t.w = w[u];
for (Ed*p = adj[u]; p; p=p->nxt)
if (p->to != fa) DFS(p->to, u);
}
int main()
{
scanf("%d", &N);
for (int i = 1; i<=N; ++i)
scanf("%d", w+i);
for (int i = 1, u, v; i<N; ++i)
{
scanf("%d%d", &u, &v);
adde(u, v), adde(v, u);
}
scanf("%d", &Q);
DFS(1, -1);
int op, a, b, w;
while (Q --) {
scanf("%d%d%d", &op, &a, &b);
if (op == 1) printf("%d\n", lct.quary(a, b));
else scanf("%d", &w), lct.makesame(a, b, w);
}
return (0 ^ 0);
}