题目描述
给定一棵树,有N(N≤100000)个节点,每一个节点都有一个权值xi xi(∣xi∣≤10000)
你需要执行Q(Q≤100000)次操作:
1 a b
查询(a,b)
这条链上的最大子段和,可以为空(即输出00)2 a b c
将(a,b)
这条链上的所有点权变为c
(∣c∣<=10000)
输入格式:
第一行一个整数N
接下来一行有N个整数表示xi
接下来N−1行,每行两个整数u,v表示u和v之间有一条边相连
接下来一行一个整数QQ
之后有Q行,每行诸如1 a b
或者2 a b c
输出格式
对于每一个询问,输出答案
此题真是数据结构大毒瘤,一开始我认为这不过是在GSS3的基础上套上一个树链剖分而已
但事实上此题细节极为多,我WA了5遍,这还是在多次在提交前一秒拍出错来的成果
看到别人说splay比线段树好写,写了LCT等等,可惜我都不会,只能用 树剖+线段树 AC
现在开始讲细节
1.线段树的区间推平
我们除了tag数组以外,还要开一个数组记录是否要推平
为什么呢,如果要变的val值为0,那么tag[o]=val,就等于0了,那么我们在pushdown的时候就会误认为不需要展开tag
加入一个数组记录是否要推平就可以避免这样的问题
void pushdown(int o,int lnum,int rnum) { if(bian[o]) { sum[o<<1]=tag[o]*lnum; lbig[o<<1]=rbig[o<<1]=mbig[o<<1]=max(0,sum[o<<1]); tag[o<<1]=tag[o]; bian[o<<1]=bian[o<<1|1]=1; sum[o<<1|1]=tag[o]*rnum; lbig[o<<1|1]=rbig[o<<1|1]=mbig[o<<1|1]=max(0,sum[o<<1|1]); tag[o<<1|1]=tag[o]; tag[o]=bian[o]=0; } }
2.树剖上区间合并
因为树剖上较为浅的点,ID值较小,所以在线段树中对应着左边
所以我们在合并的时候一定要把新query出来的结构体放在左边与ans合并
ansz=MERGE(query(id[top[u]],id[u],1,n,1),ansz); ansy=MERGE(query(id[top[v]],id[v],1,n,1),ansy);
合并的时候要记得左右分开合并
到最后将左边翻转,再合并左右
总体实现如下:
#include <algorithm> #include <iostream> #include <cmath> #include <cstring> #include <map> #include <string> #include <vector> #include <queue> #include <stack> #include <cstdio> #include <cstdlib> using namespace std; typedef long long ll; #define lson l,mid,o<<1 #define rson mid+1,r,o<<1|1 inline int read() { int a=0,q=0;char ch=getchar(); while((ch<'0'||ch>'9')&&ch!='-') ch=getchar(); if(ch=='-') q=1,ch=getchar(); while(ch>='0'&&ch<='9') a=a*10+ch-48,ch=getchar(); return q?-a:a; } const int N=100100,INF=0x3f3f3f3f; int n,m,u,v,w,op,cnt,tim,temp,top[N],dep[N],head[N],ww[N],wn[N],siz[N],fa[N],son[N],id[N],tag[N<<2],bian[N<<2],lbig[N<<2],rbig[N<<2],mbig[N<<2],sum[N<<2]; struct EDGE{int nxt,to;}e[N<<1]; void add(int u,int v){e[++cnt]=(EDGE){head[u],v};head[u]=cnt;} struct QAQ { int lb,rb,mb,s; void newone(){lb=0,rb=0,mb=0,s=0;} }; void pushup(int o) { lbig[o]=max(lbig[o<<1],lbig[o<<1|1]+sum[o<<1]); rbig[o]=max(rbig[o<<1|1],rbig[o<<1]+sum[o<<1|1]); mbig[o]=max(rbig[o<<1]+lbig[o<<1|1],max(mbig[o<<1],mbig[o<<1|1])); sum[o]=sum[o<<1]+sum[o<<1|1]; } void pushdown(int o,int lnum,int rnum) { if(bian[o]) { sum[o<<1]=tag[o]*lnum; lbig[o<<1]=rbig[o<<1]=mbig[o<<1]=max(0,sum[o<<1]); tag[o<<1]=tag[o]; bian[o<<1]=bian[o<<1|1]=1; sum[o<<1|1]=tag[o]*rnum; lbig[o<<1|1]=rbig[o<<1|1]=mbig[o<<1|1]=max(0,sum[o<<1|1]); tag[o<<1|1]=tag[o]; tag[o]=bian[o]=0; } } QAQ MERGE(QAQ xx,QAQ yy) { QAQ temp; temp.lb=max(xx.lb,yy.lb+xx.s); temp.rb=max(yy.rb,xx.rb+yy.s); temp.mb=max(xx.rb+yy.lb,max(xx.mb,yy.mb)); temp.s=xx.s+yy.s; return temp; } void build(int l,int r,int o) { if(l==r){sum[o]=wn[l];lbig[o]=rbig[o]=mbig[o]=max(sum[o],0);return;} int mid=(l+r)>>1; build(lson);build(rson); pushup(o); } QAQ query(int L,int R,int l,int r,int o) { if(L>R) return (QAQ){0,0,0,0}; if(L<=l&&r<=R){return (QAQ){lbig[o],rbig[o],mbig[o],sum[o]};} int mid=(l+r)>>1,lb,rb,mb,s=0,e1=0,e2=0; pushdown(o,mid-l+1,r-mid); QAQ temp1,temp2; if(L<=mid) e1=1,temp1=query(L,R,lson); if(R> mid) e2=1,temp2=query(L,R,rson); if(e1&&e2) { lb=max(temp1.lb,temp2.lb+temp1.s); rb=max(temp2.rb,temp1.rb+temp2.s); mb=max(temp1.rb+temp2.lb,max(temp1.mb,temp2.mb)); s=temp1.s+temp2.s; } else if(e1) { lb=temp1.lb; rb=temp1.rb; mb=temp1.mb; s=temp1.s; } else { lb=temp2.lb; rb=temp2.rb; mb=temp2.mb; s=temp2.s; } return (QAQ){lb,rb,mb,s}; } void update(int L,int R,int val,int l,int r,int o) { if(L<=l&&r<=R) { sum[o]=(r-l+1)*val; lbig[o]=rbig[o]=mbig[o]=max(0,sum[o]); tag[o]=val;bian[o]=1; return; } int mid=(l+r)>>1; pushdown(o,mid-l+1,r-mid); if(L<=mid) update(L,R,val,lson); if(R> mid) update(L,R,val,rson); pushup(o); } void dfs1(int u,int ff) { fa[u]=ff;dep[u]=dep[ff]+1;siz[u]=1; int maxson=0; for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) if(v!=ff) { dfs1(v,u); siz[u]+=siz[v]; if(siz[v]>maxson) maxson=siz[v],son[u]=v; } } void dfs2(int u,int topf) { id[u]=++tim;top[u]=topf;wn[tim]=ww[u]; if(!son[u]) return; dfs2(son[u],topf); for(int i=head[u],v=e[i].to;i;i=e[i].nxt,v=e[i].to) if(v!=fa[u]&&v!=son[u]) dfs2(v,v); } void update_tree(int u,int v,int val) { while(top[u]!=top[v]) { if(dep[top[u]]<dep[top[v]]) swap(u,v); update(id[top[u]],id[u],val,1,n,1); u=fa[top[u]]; } if(dep[u]>dep[v]) swap(u,v); update(id[u],id[v],val,1,n,1); } QAQ query_tree(int u,int v) { QAQ ansz,ansy;ansz.newone(),ansy.newone(); while(top[u]!=top[v]) { if(dep[top[u]]>=dep[top[v]]) { ansz=MERGE(query(id[top[u]],id[u],1,n,1),ansz); u=fa[top[u]]; } else { ansy=MERGE(query(id[top[v]],id[v],1,n,1),ansy); v=fa[top[v]]; } } if(dep[u]<=dep[v]) ansy=MERGE(query(id[u],id[v],1,n,1),ansy); else ansz=MERGE(query(id[v],id[u],1,n,1),ansz); swap(ansz.lb,ansz.rb); return MERGE(ansz,ansy); } int main() { // freopen("a.in","r",stdin); // freopen("b.out","w",stdout); n=read(); for(int i=1;i<=n;i++) ww[i]=read(); for(int i=1;i<n;i++) { u=read(),v=read(); add(u,v);add(v,u); } dfs1(1,1);dfs2(1,1); build(1,n,1); // for(int i=1;i<=n;i++) printf("%d ",query(i,i,1,n,1).mb); // printf(" "); m=read(); while(m--) { op=read(); if(op==1) { u=read(),v=read(); printf("%d ",query_tree(u,v).mb); } else { u=read(),v=read(),w=read(); update_tree(u,v,w); } } return 0; } /* */