题解 SP6779 【GSS7 - Can you answer these queries VII】
Juan_feng
2018-11-24 11:26:33
### NOIP之后无心刷DP题,就又来水数据结构了= =
#### 本题可以用树剖+珂朵莉树水过
**如果不了解珂朵莉树的话可以到[CF896C](https://www.luogu.org/problemnew/show/CF896C)的题解区看一下**
具体做法就是先用树剖处理一下,然后区间修改就用珂朵莉树暴力推平,区间最大子段和直接暴力去求就好啦qwq
注意一下在树剖求区间最大子段和,每次统计的时候要加上之前剩余数值(前一条链上的与当前链相连的最大子段和,因为是x, y两边同时向上跳,所以要用两个变量去保存),交换x, y的时候要同时交换对应的剩余数值,**当最后x, y在同一条链上的时候要再交换一下x,y对应的剩余数值**。(WA了好几次QAQ)
**如果有什么问题或者对题解有什么意见和建议的话欢迎私信小蒟蒻qwqwq。**
**那么代码如下:**
```
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cstdio>
#include <cmath>
#include <set>
#define re register
#define ll long long
#define maxn 200010
#define FOR(i, l, r) for(re int i = l; i <= r; ++i)
#define IT set<node>::iterator
using namespace std;
int n, m, c, r, t, x, y, z, num, cnt, sss, fir1, fir2;
int a[maxn], ans[maxn], tag[maxn], depth[maxn], fa[maxn], top[maxn], id[maxn], dd[maxn];
int son[maxn], head[maxn], siz[maxn];
struct hz {
int next;
int to;
}h[maxn];
inline void in(int &x){
x=0;int f=1;char c=getchar();
while(c<'0'||c>'9'){
if(c==-1) return;
if(c=='-')f=-1;
c=getchar();
}
while(c<='9'&&c>='0'){
x=(x<<1)+(x<<3)+(c^'0');
c=getchar();
}
x=x*f;
}
inline void out(int a){
if(a<0){
a*=-1;
putchar('-');
}
if(a>=10)out(a/10);
putchar(a%10+'0');
}
struct node{
int l;
int r;
mutable int v;
node(int L, int R = -1, int V = 0):l(L), r(R), v(V){}
bool operator <(const node &o)const {
return l < o.l;
}
};
set<node> s;
IT split(int pos) {
IT it = s.lower_bound(node(pos));
if(it != s.end() && it->l == pos)
return it;
--it;
int L = it->l;
int R = it->r;
int V = it->v;
s.erase(it);
s.insert(node(L, pos-1, V));
return s.insert(node(pos, R, V)).first;
}
void assign_val(int l, int r, int val = 0) { //推平
IT itr = split(r+1), itl = split(l);
s.erase(itl, itr);
s.insert(node(l, r, val));
}
int query(int l, int r) { //暴力统计
IT itr = split(r+1), itl = split(l);
int anss = fir1;
int res = fir1;
--itr;
--itl;
for(; itl != itr; --itr) {
res += (itr->r-itr->l+1)*itr->v;
if(res > anss)
anss = res;
if(res < 0)
res = 0;
}
fir1 = res;
return anss;
}
void add(int from, int to) {
h[++num].next = head[from];
h[num].to = to;
head[from] = num;
}
void dfs1(int f, int ff) { //树剖预处理
fa[f] = ff;
depth[f] = depth[ff]+1;
siz[f] = 1;
for(re int i = head[f]; i != 0; i = h[i].next) {
if(h[i].to == ff)
continue;
dfs1(h[i].to, f);
siz[f] += siz[h[i].to];
if(siz[h[i].to] > siz[son[f]])
son[f] = h[i].to;
}
}
void dfs2(int x, int topf) { //同上
top[x] = topf;
id[x] = ++cnt;
dd[cnt] = a[x];
if(!son[x])
return;
dfs2(son[x], topf);
for(re int i = head[x]; i != 0; i = h[i].next) {
if(h[i].to == fa[x] || h[i].to == son[x])
continue;
dfs2(h[i].to, h[i].to);
}
}
void updrange(int x, int y, int k) { //推平
while(top[x] != top[y]) {
if(depth[top[x]] < depth[top[y]])
swap(x, y);
assign_val(id[top[x]], id[x], k);
x = fa[top[x]];
}
if(depth[x] > depth[y])
swap(x, y);
assign_val(id[x], id[y], k);
}
int qrange(int x, int y) { //区间最大子段和
int anss = 0;
while(top[x] != top[y]) {
if(depth[top[x]] < depth[top[y]]) {
swap(x, y);
swap(fir1, fir2); //注意
}
anss = max(anss, query(id[top[x]], id[x]));
x = fa[top[x]];
}
if(depth[x] > depth[y]) {
swap(x, y);
swap(fir1, fir2); //注意
}
swap(fir1, fir2); //最后要再交换一下
anss = max(anss, query(id[x], id[y]));
anss = max(anss, fir1+fir2);
return anss;
}
//void ts(int l, int r) { //用于调试
// cout << endl;
// IT itr = split(r+1), itl = split(l);
// for(; itl != itr; ++itl)
// FOR(i, 1, itl->r-itl->l+1)
// cout << itl->v << " ";
// cout << endl;
// return;
//}
int main() {
in(n);
FOR(i, 1, n)
in(a[i]);
FOR(i, 1, n-1) {
in(x), in(y);
add(x, y);
add(y, x);
}
dfs1(1, 0);
dfs2(1, 1);
FOR(i, 1, n)
s.insert(node(i, i, dd[i]));
s.insert(node(1, n+233, 0));
in(m);
FOR(i, 1, m) {
in(t);
if(t == 1) {
in(x), in(y);
fir1 = 0;
fir2 = 0;
out(qrange(x, y));
putchar(10);
}
else {
in(x), in(y), in(z);
updrange(x, y, z);
}
}
}
```