1. 程式人生 > >SPOJ 6779 GSS7 - Can you answer these queries VII

SPOJ 6779 GSS7 - Can you answer these queries VII

題目描述

給定一棵樹,有N(N100000)個節點,每一個節點都有一個權值xi xi(xi10000)

你需要執行Q(Q100000)次操作:

  1. 1 a b 查詢(a,b)這條鏈上的最大子段和,可以為空(即輸出00)
  2. 2 a b c 將(a,b)這條鏈上的所有點權變為c (c<=10000)

輸入格式:

第一行一個整數N

接下來一行有N個整數表示xi

接下來N1行,每行兩個整數u,v表示uv之間有一條邊相連

接下來一行一個整數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;
}
/*

*/