Spoj 6779 Can you answer these queries VII 树链剖分 在树上任意路径的最大子段和 区间修改点权

题目链接:点击打开链接

题意:

rt。。

在询问时,两端向上爬时记录从深度浅的到深度深的方向上的 (也就是左最大连续子段和)

最后两个点在同一条重链上时合并。

合并时要注意有4种情况, 详见代码。

线段树部分和5相似。

#include <cstdio>
#include <iostream>
#include <string.h>
#include <vector>
using namespace std;
inline void rd(int &n){
	n = 0;
    bool tmp = 0;
    char c = getchar();
    while((c < '0' || c > '9') && c != '-' ) c = getchar();
    if(c == '-') c = getchar(), tmp = 1;
    while(c >= '0' && c <= '9') n *= 10, n += (c - '0'),c = getchar();
	if(tmp) n = -n;
}
#define N 100100
#define hehe 10001
#define L(x) tree[x].l
#define R(x) tree[x].r
#define Lson(x) (x<<1)
#define Rson(x) (x<<1|1)
#define Sum(x) tree[x].sum
#define Max(x) tree[x].max
#define Lmax(x) tree[x].lmax
#define Rmax(x) tree[x].rmax
#define Lazy(x) tree[x].lazy
#define Siz(x) tree[x].siz()
struct node{
    int l, r;
    int mid(){return (l+r)>>1;}
	int siz(){return r-l+1;}
    int lmax, rmax, max, sum, lazy;
}tree[N<<2];
int n, a[N], Q, fw[N];
void updata_point(int val, int id){Lmax(id) = Rmax(id) = Max(id) = Sum(id) = val * Siz(id);}
void push_down(int id){
	if(L(id) == R(id))return ;
	if(Lazy(id)!=hehe) {
		updata_point(Lazy(id), Lson(id));
		updata_point(Lazy(id), Rson(id));
		Lazy(Lson(id)) = Lazy(Rson(id)) = Lazy(id);
		Lazy(id) = hehe;
	}
}
void push_up(int id){
	if(L(id)==R(id))return ;
    Lmax(id) = max(Lmax(Lson(id)), Sum(Lson(id)) + Lmax(Rson(id)));
    Rmax(id) = max(Rmax(Rson(id)), Sum(Rson(id)) + Rmax(Lson(id)));
    Sum(id) = Sum(Lson(id)) + Sum(Rson(id));
    Max(id) = max(max(Max(Lson(id)), Max(Rson(id))), Rmax(Lson(id)) + Lmax(Rson(id)));
}
void build(int l, int r, int id){
    L(id) = l; R(id) = r;
	Lazy(id) = hehe;
    if(l == r)
    {
        updata_point(a[fw[l]], id);
        return;
    }
    int mid = tree[id].mid();
    build(l, mid, Lson(id));
    build(mid+1, r, Rson(id));
    push_up(id);
}
void updata(int l, int r, int val, int id){
    push_down(id);
    if(l == L(id) && R(id) == r)
    {
		Lazy(id) = val;
        updata_point(val, id);
        return ;
    }
    int mid = tree[id].mid();
    if(mid < l)
        updata(l, r, val, Rson(id));
    else if(r <= mid)
        updata(l, r, val, Lson(id));
	else {
		updata(l, mid, val, Lson(id));
		updata(mid+1, r, val, Rson(id));
	}
    push_up(id);
}
int query_sum(int l, int r, int id){
	push_down(id);
	if(l == L(id) && R(id) == r) return Sum(id);
	int mid = tree[id].mid();
	if(mid < l)
		return query_sum(l, r, Rson(id));
	else if(r <= mid)
		return query_sum(l, r, Lson(id));
	else
		return query_sum(l, mid, Lson(id)) + query_sum(mid+1, r, Rson(id));
}
int query_L(int l, int r, int id){
    if(l == L(id) && R(id) == r) return Lmax(id);
    int mid = tree[id].mid();
    if(mid < l)
        return query_L(l, r, Rson(id));
    else if(r <= mid)
        return query_L(l, r, Lson(id));
    int lans = query_L(l, mid, Lson(id)), rans = query_L(mid+1, r, Rson(id));
    return max(lans, query_sum(l, mid, id) + rans);
}
int query_R(int l, int r, int id){
    if(l == L(id) && R(id) == r) return Rmax(id);
    int mid = tree[id].mid();
    if(mid < l)
        return query_R(l, r, Rson(id));
    else if(r <= mid)
        return query_R(l, r, Lson(id));
    int lans = query_R(l, mid, Lson(id)), rans = query_R(mid+1, r, Rson(id));
    return max(rans, query_sum(mid+1, r, id) + lans);
}
int query_l(int l, int r, int id){
    push_down(id);
    if(l == L(id) && R(id) == r) return Lmax(id);
    int mid = tree[id].mid();
    if(mid < l)
        return query_l(l, r, Rson(id));
    else if(r <= mid)
        return query_l(l, r, Lson(id));
    int lans = query_l(l, mid, Lson(id)), rans = query_l(mid+1, r, Rson(id));
    return max(lans, Sum(Lson(id)) + rans);
}
int query_r(int l, int r, int id){
    push_down(id);
    if(l == L(id) && R(id) == r) return Rmax(id);
    int mid = tree[id].mid();
    if(mid < l)
        return query_r(l, r, Rson(id));
    else if(r <= mid)
        return query_r(l, r, Lson(id));
    int lans = query_r(l, mid, Lson(id)), rans = query_r(mid+1, r, Rson(id));
    return max(rans, Sum(Rson(id)) + lans);
}
int query(int l, int r, int id){
    push_down(id);
    if(l == L(id) && R(id) == r)return Max(id);
    int mid = tree[id].mid();
    if(mid < l)
        return query(l, r, Rson(id));
    else if(r<=mid)
        return query(l, r, Lson(id));
    int lans = query(l, mid, Lson(id)), rans = query(mid+1, r, Rson(id));
    int ans = max(lans, rans);
    return max(ans, query_r(l, mid, Lson(id)) + query_l(mid+1, r, Rson(id)));
}
vector<int>G[N];
int fa[N], son[N], siz[N], dep[N], tree_id;
//父节点 重儿子 子树节点数 深度 线段树标号
int w[N], p[N];
//父边在线段树中的标号 节点顶端的点
void dfs(int u, int Father, int deep){
	fa[u] = Father;	son[u] = 0;	dep[u] = deep; siz[u] = 1;
	for(int i = 0; i < G[u].size(); i++) {
		int v = G[u][i]; if(v == Father) continue;
		dfs(v, u, deep+1);
		siz[u] += siz[v];
		if(siz[v] > siz[son[u]])son[u] = v;
	}
}
void Have_p(int u, int Father){
	w[u] = ++ tree_id; fw[tree_id] = u; p[u] = Father;
	if(son[u])
		Have_p(son[u], Father);
	else return ;
	for(int i = 0; i < G[u].size(); i++) {
		int v = G[u][i]; if(v == fa[u] || v == son[u])continue;
		Have_p(v, v);
	}
}
void Updata(int l, int r, int val){
	int f1 = p[l], f2 = p[r];
	while(f1 != f2) {
		if(dep[f1] < dep[f2])
			swap(f1, f2), swap(l, r);
		updata(w[f1], w[l], val, 1);
		l = fa[f1]; f1 = p[l];
	}
	if(dep[l] > dep[r]) swap(l, r);
	updata(w[l], w[r], val, 1);
}
int Query(int l, int r){
	int ans = 0;
	int f1 = p[l], f2 = p[r], lmax = 0, rmax = 0;
	while(f1 != f2) {
		if(dep[f1] < dep[f2])
			swap(f1, f2), swap(l, r), swap(lmax, rmax);
		ans = max(ans, query(w[f1], w[l], 1));
		ans = max(ans, max(0,query_R(w[f1], w[l], 1)) + lmax);
		lmax = max(query_sum(w[f1], w[l], 1) + lmax, query_L(w[f1], w[l], 1));
		lmax = max(0, lmax);
		l = fa[f1]; f1 = p[l];
	}
	if(dep[l] > dep[r]) swap(l, r), swap(lmax, rmax);
	ans = max(ans, query(w[l], w[r], 1));
	ans = max(ans, query_L(w[l], w[r], 1) + lmax);
	ans = max(ans, query_R(w[l], w[r], 1) + rmax);
	ans = max(ans, query_sum(w[l], w[r], 1) + lmax + rmax);
	return ans;
}
void solve(){
	siz[0] = tree_id = 0;
	dfs(1, 1, 1);
	Have_p(1, 1);
	build(1, n, 1);
	rd(Q); int op, a, b, c;
	while(Q--)
	{
		rd(op); rd(a); rd(b);
		if(op == 1)
			printf("%d\n", Query(a, b));
		else
		{
			rd(c);
			Updata(a, b, c);
		}
	}
}
void input(){
	for(int i = 1; i <= n; i++)rd(a[i]), G[i].clear();
	for(int u, v, i = 1; i < n; i++) {
		 rd(u); rd(v);
		 G[u].push_back(v); G[v].push_back(u);
	}
}
int main(){
    while(~scanf("%d",&n)){
        input();
		solve();
    }
    return 0;
}
/*
7
-5 7 4 3 -5 8 -3
1 2
1 3
2 4
2 5
5 6
5 7
8
1 4 3
2 1 1 -3
1 3 4

1 2 6
1 6 2
1 2 7
1 7 5
1 4 7
ans :
10
11
10
10
7
0
10

*/
时间: 2024-10-03 18:14:49

Spoj 6779 Can you answer these queries VII 树链剖分 在树上任意路径的最大子段和 区间修改点权的相关文章

SPOJ GSS7 Can you answer these queries VII

Can you answer these queries VII Time Limit: 1000ms Memory Limit: 262144KB This problem will be judged on SPOJ. Original ID: GSS764-bit integer IO format: %lld      Java class name: Main Given a tree with N ( N<=100000 ) nodes. Each node has a interg

SPOJ 375 QTREE - Query on a tree(树链剖分)

题目链接:http://www.spoj.com/problems/QTREE/en/ 题意:  一棵树 n 个节点,每条边上有权值,同时有两个操作: (1)更改操作:CHANGE i ti(把第 i 条边上的权值改为 ti). (2)查询操作:QUERY a b(查询 a 到 b 的路径上权值最大的边的权值). 思路(树链剖分): 看到这种区间查询的题想要用数据结构优化,提高时间效率一般会想到线段树.可是这次操作的对象并不是一组序列, 无法直接使用线段树.这时,我们可以做些转化:对树作树链剖分

SPOJ 1043 Can you answer these queries I 求任意区间最大连续子段和 线段树

题目链接:点击打开链接 维护区间左起连续的最大和,右起连续的和.. #include <cstdio> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <vector> #include <map> using namespace std; #define N 50050 #define Lson

SPOJ 4487. Can you answer these queries VI splay

题目链接:点击打开链接 题意比较明显,不赘述. 删除时可以把i-1转到根,把i+1转到根下 则i点就在 根右子树 的左子树,且只有i这一个 点 #include<stdio.h> #include<iostream> #include<string.h> #include<algorithm> using namespace std; #define N 300500 #define inf 10000000 #define L(x) tree[x].ch[

SPOJ GSS3 Can you answer these queries III (线段树)

题目大意: 求区间最大子区间的和. 思路分析: 记录左最大,右最大,区间最大. 注意Q_L  和 Q_R  就好. #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #define lson num<<1,s,mid #define rson num<<1|1,mid+1,e #define maxn 55555 using na

SPOJ GSS4 Can you answer these queries IV (线段树)

题目大意: 给出N个数 0     操作   把 l -----  r之间的数全部开平方 1     操作  输出 l -----r  之间的和 思路分析: 判断区间里的数字是否全相同.如果相同, 将cov 置为该数 查询的时候和更新的时候,如果碰到cov != -1 的  就直接返回就可以了 #include <cstdio> #include <iostream> #include <algorithm> #include <cstring> #incl

spoj gss2 : Can you answer these queries II 离线&amp;&amp;线段树

1557. Can you answer these queries II Problem code: GSS2 Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse to write two program of same kind at all. So he always failes in co

SPOJ GSS5 Can you answer these queries V (线段树)

原来有一两个人说我不帅的时候,我不以为意,逗我玩而已,后来几乎所有 人都说我不帅,我才真正意识到事态的严重,这社会骗子真是越来越多了... 好吧我承认,这个笑话不好笑,其实我想说的是,做人一定要坚持自己的原则, 哪怕有一天所有人都和你背道而驰,都不要放弃自己当初的梦想,如果有一天, 我们淹没在人海之中,庸碌一生,那是因为我们不够努力,不够勇敢的去面对生活. 每天积累一点点,嗯,满足简单的快乐. ---------------------------------------------------

HDU4027 Can you answer these queries 线段树区间求和+剪枝

给了你n,然后n个数字在一个数组中,接下来m个询问,每个询问三个数字 t,x,y,若t==0,那么修改区间[x,y]的每一个值,变为原来每个位置上的数 开根号取整,若t==1,那么对区间[x,y]求和 由于n,m,很大,所以树状数组铁定超时,若直接用线段树来做区间修改,那么也是超时,这类题目没别的方法了,静心剪枝,发现题目给的数据范围为2^63,有没有发现,2^63开根号 绝对不需要开10次,就能到1,到1以后就不需要再开了,意思就是若有某个区间[x,y]每一个点的值都为1时,这一段区间事实上是