SPOJ GSS7 Can you answer these queries VII(LCT)

题意:维修数列的树上路径版,操作:将一段路径上的点权设为同一个值,求一段路径上的最大字段和。

坑了我好大半天!!!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);
}



  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值