4127: Abs
Time Limit: 40 Sec Memory Limit: 256 MBSubmit: 667 Solved: 225
[ Submit][ Status][ Discuss]
Description
给定一棵树,设计数据结构支持以下操作 1 u v d 表示将路径 (u,v) 加d 2 u v 表示询问路径 (u,v) 上点权绝对值的和
Input
第一行两个整数n和m,表示结点个数和操作数
接下来一行n个整数a_i,表示点i的权值 接下来n-1行,每行两个整数u,v表示存在一条(u,v)的边 接下来m行,每行一个操作,输入格式见题目描述
Output
对于每个询问输出答案
Sample Input
4 4
-4 1 5 -2
1 2
2 3
3 4
2 1 3
1 1 4 3
2 1 3
2 3 4
Sample Output
10
13
9
写完之后BUG一段,TLE+WA+RE了快50发
线段树节点存三个值:最大的负数,负数的个数,当前绝对值大小
叶子结点多存一个实际值
区间修改查询就直接区间操作
如果当前修改的那个区间全是正数或者最大的负数+当前值后还是负数,就懒惰
否则暴力修改
因为每次加的值都是正数,所以每个数改变符号只会发生1次,暴力操作只会进行n次,复杂度额外的O(nlogn)
#pragma comment(linker, "/STACK:102400000,102400000")
#include<stdio.h>
#include<stdlib.h>
#include<vector>
#include<algorithm>
using namespace std;
#define LL long long
typedef struct
{
int to;
int next;
}Road;
Road G[200005];
typedef struct Tree
{
LL sum, rit;
int mat, bet;
Tree operator + (const Tree &b) const
{
Tree now;
now.sum = sum+b.sum;
now.mat = mat+b.mat;
if(bet>=0)
now.bet = b.bet;
else if(b.bet>=0)
now.bet = bet;
else
now.bet = max(bet, b.bet);
return now;
}
}Tree;
Tree tre[844444];
int head[150005], val[150005], fa[150005], son[150005], siz[150005], dep[150005];
int n, xt, cnt, rak[150005], id[150005], top[150005];
LL temp[844444];
void Add(LL u, LL v)
{
cnt++;
G[cnt].next = head[u];
head[u] = cnt;
G[cnt].to = v;
}
void Sech1(int u, int p)
{
int i, v;
fa[u] = p;
dep[u] = dep[p]+1;
for(i=head[u];i!=0;i=G[i].next)
{
v = G[i].to;
if(v==p)
continue;
Sech1(v, u);
siz[u] += siz[v]+1;
if(son[u]==0 || siz[v]>siz[son[u]])
son[u] = v;
}
}
void Sech2(int u, int p)
{
int i, v;
top[u] = p;
rak[u] = ++xt, id[xt] = u;
if(son[u]==0)
return;
Sech2(son[u], p);
for(i=head[u];i!=0;i=G[i].next)
{
v = G[i].to;
if(son[u]==v || fa[u]==v)
continue;
Sech2(v, v);
}
}
void Lazy(int l, int r, int x);
LL Query(int l, int r, int x, int a, int b);
void Create(int l, int r, int x);
void Update(int l, int r, int x, int a, int b, int c);
void Update_Tre(int x, int y, int d)
{
int p1, p2;
p1 = top[x], p2 = top[y];
while(p1!=p2)
{
if(dep[p1]<dep[p2])
swap(x, y), swap(p1, p2);
Update(1, n, 1, rak[p1], rak[x], d);
x = fa[p1], p1 = top[x];
}
if(dep[x]>dep[y])
swap(x, y);
Update(1, n, 1, rak[x], rak[y], d);
}
LL Query_Tre(int x, int y)
{
LL sum = 0;
int p1, p2;
p1 = top[x], p2 = top[y];
while(p1!=p2)
{
if(dep[p1]<dep[p2])
swap(x, y), swap(p1, p2);
sum += Query(1, n, 1, rak[p1], rak[x]);
x = fa[p1], p1 = top[x];
}
if(dep[x]>dep[y])
swap(x, y);
sum += Query(1, n, 1, rak[x], rak[y]);
return sum;
}
int main(void)
{
int m, i, x, y, opt, d;
//freopen("in.txt", "r", stdin);
scanf("%d%d", &n, &m);
for(i=1;i<=n;i++)
scanf("%d", &val[i]);
for(i=1;i<=n-1;i++)
{
scanf("%d%d", &x, &y);
Add(x, y);
Add(y, x);
}
Sech1(1, -1);
Sech2(1, 1);
Create(1, n, 1);
while(m--)
{
scanf("%d%d%d", &opt, &x, &y);
if(opt==1)
{
scanf("%d", &d);
Update_Tre(x, y, d);
}
else
printf("%lld\n", Query_Tre(x, y));
}
return 0;
}
void Create(int l, int r, int x)
{
int m;
if(l==r)
{
tre[x].rit = val[id[r]];
tre[x].sum = abs(tre[x].rit);
tre[x].bet = tre[x].rit;
if(tre[x].rit<0)
tre[x].mat = 1;
else
tre[x].mat = 0;
return;
}
m = (l+r)/2;
Create(l, m, x*2);
Create(m+1, r, x*2+1);
tre[x] = tre[x*2]+tre[x*2+1];
}
void Update(int l, int r, int x, int a, int b, int c)
{
int m;
if(l==r)
{
tre[x].rit += c;
tre[x].sum = abs(tre[x].rit);
tre[x].bet = tre[x].rit;
if(tre[x].rit<0)
tre[x].mat = 1;
else
tre[x].mat = 0;
return;
}
if(temp[x])
Lazy(l, r, x);
if(l>=a && r<=b && (tre[x].mat==0 || tre[x].bet+c<0))
{
tre[x].bet += c;
tre[x].sum += (LL)(r-l+1-2*tre[x].mat)*c;
temp[x] += c;
return;
}
m = (l+r)/2;
if(a<=m)
Update(l, m, x*2, a, b, c);
if(b>=m+1)
Update(m+1, r, x*2+1, a, b, c);
tre[x] = tre[x*2]+tre[x*2+1];
}
LL Query(int l, int r, int x, int a, int b)
{
int m;
LL sum = 0;
if(l>=a && r<=b)
return tre[x].sum;
if(temp[x])
Lazy(l, r, x);
m = (l+r)/2;
if(a<=m)
sum += Query(l, m, x*2, a, b);
if(b>=m+1)
sum += Query(m+1, r, x*2+1, a, b);
return sum;
}
void Lazy(int l, int r, int x)
{
int m;
m = (l+r)/2;
tre[x*2].bet += temp[x];
tre[x*2+1].bet += temp[x];
tre[x*2].sum += (m-l+1-2*tre[x*2].mat)*temp[x];
tre[x*2+1].sum += (r-m-2*tre[x*2+1].mat)*temp[x];
if(l==m)
tre[x*2].rit += (m-l+1)*temp[x];
if(m+1==r)
tre[x*2+1].rit += (r-m)*temp[x];
if(l<m)
temp[x*2] += temp[x];
if(r>m+1)
temp[x*2+1] += temp[x];
temp[x] = 0;
}
/*
5 100
-2 -1 0 1 2
1 2 2 3 3 4 4 5
1 1 5 2
2 1 5
*/