SPOJ-GSS7 Can you answer these queries VII(树上区间最大和)

Given a tree with N (N <= 100000) nodes. Each node has a interger value x_i (|x_i|<= 10000).

You have to apply Q (Q <= 100000) operations:

1. 1 a b : answer the maximum contiguous sum (maybe empty,will always larger than or equal to 0 ) from the path a->b ( inclusive ).

2. 2 a b c : change all value in the path a->b ( inclusive ) to c. (|c| <= 10000)

Input

first line consists one interger N.

next line consists N interger x_i.

next N-1 line , each consists two interger u,v , means that node u and node v are connected

next line consists 1 interger Q.

next Q line : 1 a b or 2 a b c .

Output

For each query, output one line the maximum contiguous sum.

Example

Input:
5
-3 -2 1 2 3
1 2
2 3
1 4
4 5
3
1 2 5
2 3 4 2
1 2 5

Output:
5

9

题意:给一点权棵树,有两个操作,修改和查询,每次修改u 到 v路径上所有的点权,每次查询u 到 v路径上的最大连续区间和。

分析:类似线段树的做法,每次push_up时分类讨论一下就可以了。

#include <cstdio>
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
#include <cstring>
#define MAXN 100015
#define NONE 10001
using namespace std;
int n,q,op,u,v,c,lc[MAXN],rc[MAXN],ch[MAXN][2],s[MAXN],size[MAXN],sum[MAXN],maxsum[MAXN],value[MAXN],fa[MAXN],lazy2[MAXN];
bool lazy[MAXN];
inline bool isroot(int x)
{
	return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}
void push_up(int x)
{
	lc[0] = rc[0] = maxsum[0] = sum[0] = size[0] = 0;
	size[x] = size[ch[x][0]] + 1 + size[ch[x][1]];
	sum[x] = sum[ch[x][0]] + value[x] + sum[ch[x][1]];
	maxsum[x] = max(maxsum[ch[x][0]],maxsum[ch[x][1]]);
	maxsum[x] = max(maxsum[x],rc[ch[x][0]] + value[x] + lc[ch[x][1]]);
	lc[x] = max(lc[ch[x][0]],sum[ch[x][0]] + value[x] + lc[ch[x][1]]);
	rc[x] = max(rc[ch[x][1]],sum[ch[x][1]] + value[x] + rc[ch[x][0]]);
}
void rotate(int x)
{
	int y = fa[x],z = fa[y];
	int d = ch[y][0] == x ? 0 : 1;
	if(!isroot(y))
	{
		if(ch[z][0] == y) ch[z][0] = x;
		else ch[z][1] = x;
	}
	fa[y] = x,fa[x] = z,fa[ch[x][d^1]] = y;
	ch[y][d] = ch[x][d^1],ch[x][d^1] = y;
	push_up(y),push_up(x);
}
void change(int x,int y)
{
	lazy2[x] = value[x] = y;
	maxsum[x] = rc[x] = lc[x] = y > 0 ? size[x]*y : 0;
	sum[x] = size[x]*y;
}
inline void push_down(int x)
{
	if(lazy[x])
	{
		int ls = ch[x][0],rs = ch[x][1];
		lazy[x]^=1,lazy[ls]^=1;lazy[rs]^=1;
		swap(ch[ls][0],ch[ls][1]);
		swap(ch[rs][0],ch[rs][1]);
		swap(lc[ls],rc[ls]);
		swap(lc[rs],rc[rs]);
	}
	if(lazy2[x] != NONE)
	{
		change(ch[x][0],lazy2[x]),change(ch[x][1],lazy2[x]);
		lazy2[x] = NONE;
	}
}
void splay(int x)
{
	int tot = 0;s[++tot] = x;
	for(int i = x;!isroot(i);i = fa[i]) s[++tot] = fa[i];
	for(;tot;tot--) push_down(s[tot]);
	while(!isroot(x))
	{
		int y = fa[x],z = fa[y];
		if(!isroot(y))
		{
			if((ch[z][0] == y) ^ (ch[y][0] == x)) rotate(x);
			else rotate(y);
		}
		rotate(x);
	}
}
void access(int x)
{
	int t = 0;
	while(x)
	{
		splay(x);
		ch[x][1] = t;          //parent path 边中儿子一定是子链root,父亲是子链root实际父亲 
		push_up(x);
		t = x,x = fa[x];
	}
}
void makeroot(int x)        //x变成根 
{
	access(x),splay(x);
	swap(ch[x][0],ch[x][1]);
	lazy[x]^=1; 
}
void link(int x,int y)
{
	makeroot(x);fa[x] = y;
}
int main()
{
	scanf("%d",&n);
	for(int i = 1;i <= n;i++) 
	{
		scanf("%d",&value[i]);
		maxsum[i] = lc[i] = rc[i] = max(0,value[i]); 
		size[i] = 1,sum[i] = value[i];
		lazy2[i] = NONE;
	}
	for(int i = 1;i < n;i++)
	{
		scanf("%d%d",&u,&v);
		link(u,v);
	}
	scanf("%d",&q);
	for(int i = 1;i <= q;i++)
	{
		scanf("%d",&op);
		if(op == 1)
		{
			scanf("%d%d",&u,&v);
			makeroot(u);
			access(v);
			splay(v);
			printf("%d\n",maxsum[v]);
		}
		else
		{
			scanf("%d%d%d",&u,&v,&c);
			makeroot(u);
			access(v);
			splay(v);
			change(v,c);
		}
	}
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值