据说是一道很裸的树链剖分,但是我感觉树链剖分并不是很好写。。。然后就行LCT写了,很裸的LCT,但是这道题居然RE, dfs爆栈了,然后我把vector存边换成结构体居然就过了!!!大家好像是dfs的时候把根换点就能过了。
本题题意:有两个操作,1:把u->v的链上的点全部变成w。2:找出u->v这条链上最大非空区间和,这个就是把左右两段合起来。
附上ac代码:
#include <cstring>
#include <cmath>
#include <algorithm>
#include <cstdio>
#include <vector>
#define LL long long
#define INF 0x3fffffff
#define FOR(i,x,y) for(int i = x;i < y;i ++)
#define IFOR(i,x,y) for(int i = x;i > y;i --)
#define MAXN 440000
using namespace std;
int n,m;
int head[MAXN],edge_cnt;
struct Edge{
int u,v;
int nt;
}edge[MAXN<<1];
void add_edge(int u,int v){
edge[edge_cnt].u = u;
edge[edge_cnt].v = v;
edge[edge_cnt].nt = head[u];
head[u] = edge_cnt++;
}
struct LCT{
int pre[MAXN],ch[MAXN][2],flip[MAXN];
int key[MAXN];
int ans[MAXN],l[MAXN],r[MAXN],sum[MAXN],lazy[MAXN],sz[MAXN];
bool mk[MAXN];
bool rt[MAXN];
void Update_Lazy(int x,int w){
if(!x) return;
lazy[x] = w;
key[x] = w;
sum[x] = sz[x] * w;
ans[x] = w>0 ? (sz[x]*w) : w;
l[x] = ans[x];
r[x] = ans[x];
mk[x] = true;
}
void Update_Flip(int x){
if(!x) return;
swap(l[x],r[x]);
swap(ch[x][0],ch[x][1]);
flip[x] ^= 1;
}
void Init(){
memset(ch,0,sizeof(ch));
memset(flip,0,sizeof(flip));
memset(rt,true,sizeof(rt));
memset(mk,false,sizeof(mk));
memset(lazy,-1,sizeof(lazy));
sz[0] = sum[0] = key[0] = l[0] = r[0] = ans[0] = 0;
FOR(i,1,n+1){
ans[i] = sum[i] = l[i] = r[i] = key[i];
sz[i] = 1;
}
}
void PushUp(int x){
sz[x] = 1 + sz[ch[x][0]] + sz[ch[x][1]];
sum[x] = key[x] + sum[ch[x][0]] + sum[ch[x][1]];
if(ch[x][0]){
l[x] = max(max(l[ch[x][0]],sum[ch[x][0]]+key[x]),sum[ch[x][0]]+key[x]+l[ch[x][1]]);
}
else
l[x] = max(key[x],key[x]+l[ch[x][1]]);
if(ch[x][1]){
r[x] = max(max(r[ch[x][1]],sum[ch[x][1]]+key[x]),sum[ch[x][1]]+key[x]+r[ch[x][0]]);
}
else
r[x] = max(key[x],key[x]+r[ch[x][0]]);
int t = key[x] + (l[ch[x][1]] > 0 ? l[ch[x][1]] : 0) + (r[ch[x][0]] > 0 ? r[ch[x][0]] : 0);
if(ch[x][0] && ch[x][1]){
ans[x] = max(max(ans[ch[x][0]],ans[ch[x][1]]),t);
}
else if(ch[x][0]){
ans[x] = max(ans[ch[x][0]],t);
}
else if(ch[x][1]){
ans[x] = max(ans[ch[x][1]],t);
}
else ans[x] = t;
}
void PushDown(int x){
if(mk[x]){
Update_Lazy(ch[x][0],lazy[x]);
Update_Lazy(ch[x][1],lazy[x]);
mk[x] = false;
}
if(flip[x]){
Update_Flip(ch[x][0]);
Update_Flip(ch[x][1]);
flip[x] = 0;
}
}
void Rotate(int x,int kind){
int y = pre[x];
PushDown(y);
PushDown(x);
ch[y][!kind] = ch[x][kind];
if(ch[x][kind]) pre[ch[x][kind]] = y;
if(rt[y]){
rt[x] = true;
rt[y] = false;
}
else{
if(ch[pre[y]][1] == y) ch[pre[y]][1] = x;
if(ch[pre[y]][0] == y) ch[pre[y]][0] = x;
}
pre[x] = pre[y];
pre[y] = x;
ch[x][kind] = y;
PushUp(y);
}
void Splay(int x){
PushDown(x);
while(!rt[x]){
int y = pre[x];
int z = pre[y];
if(rt[y]){
PushDown(y); PushDown(x);
Rotate(x,ch[y][0] == x);
}
else{
PushDown(z); PushDown(y); PushDown(x);
int kind = ch[z][0] == y;
if(ch[y][kind] == x){
Rotate(x,!kind);
Rotate(x,kind);
}
else{
Rotate(y,kind);
Rotate(x,kind);
}
}
}
PushUp(x);
}
void Access(int x){
int fa = 0;
for(;x;x = pre[fa = x]){
Splay(x);
rt[ch[x][1]] = true;
rt[ch[x][1] = fa] = false;
PushUp(x);
}
}
int GetRoot(int x){
Access(x);
Splay(x);
while(ch[x][0]) x = ch[x][0];
return x;
}
void MakeRoot(int x){
Access(x);
Splay(x);
Update_Flip(x);
}
void Modify(int u,int v,int w){
MakeRoot(u);
Access(v);
Splay(v);
Update_Lazy(v,w);
}
int Query(int u,int v){
MakeRoot(u);
Access(v);
Splay(v);
return ans[v];
}
}lct;
void dfs(int u,int fa){
lct.pre[u] = fa;
for(int i = head[u];i != -1;i = edge[i].nt){
int v = edge[i].v;
if(v == fa) continue;
dfs(v,u);
}
}
int main(){
//freopen("test.in","r",stdin);
while(~scanf("%d%d",&n,&m)){
FOR(i,1,n+1) scanf("%d",&lct.key[i]);
edge_cnt = 0;
memset(head,-1,sizeof(head));
FOR(i,1,n){
int u,v;
scanf("%d%d",&u,&v);
add_edge(u,v);
add_edge(v,u);
}
dfs(1,0);
lct.Init();
int op;
int u,v;
int w;
FOR(i,0,m){
scanf("%d",&op);
if(op == 2){
scanf("%d%d%d",&u,&v,&w);
printf("%d\n",lct.Query(u,v));
}
else{
scanf("%d%d%d",&u,&v,&w);
lct.Modify(u,v,w);
}
}
}
return 0;
}