SPOJ 6779 GSS7 - Can you answer these queries VII
阿新 • • 發佈:2018-12-03
題目描述
給定一棵樹,有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("\n"); m=read(); while(m--) { op=read(); if(op==1) { u=read(),v=read(); printf("%d\n",query_tree(u,v).mb); } else { u=read(),v=read(),w=read(); update_tree(u,v,w); } } return 0; } /* */