codechef Queries on tree again!

一开始以为是个仙人掌,于是拿圆方树写,然后发现边上的权值用圆方树很难维护。但是注意到只有一个环,所以就分两种情况进行树链剖分。把环上的每一个点都看作一颗树根,然后分两种情况剖分。
1.当u,v在通一颗子树上,就是普通的树链剖分了
2.u,v在不同子树上,把u子树上的路径,v子树上的路径,和环上的最短路径合并起来即可。
然鹅题目要我们维护的是一个最大子段和,这种东西当然要用线段树维护了。线段树维护以下几个信息:
1.lmx 区间内与左端点相连的最大子段和
2.lmn 区间内与左端点相连的最小子段和
3.rmx 区间内与右端点相连的最大子段和
4.rmn 区间内与右端点相连的最小子段和
5.mx 区间内的最大子段和
6.mn 区间内的最小子段和
7.sum 区间内所有边的和
合并操作显然。不过由于两条路径(v,lca),(lca,u)中,有v->lca(大编号到小编号),lca->u(小编号到大编号),所以线段树我们要维护两个最大子段和。注意到我们要把边上的权值转移到点上,所以要避免计算lca的贡献。

#include
using namespace std;
const int N=3e5+5;
int n,id,up,q,sum,cnt,a[N],x,y,lg[N],s[N],b[N],Id[N],f[N],ff[N][20],rev[N],dis[N],dfn[N],low[N],head[N],nex[N],to[N],wi[N];
int dep[N],si[N],fa[N],son[N],top[N],vis[N];
int tot=1;void add(int u,int v,int w){to[++tot]=v;nex[tot]=head[u];head[u]=tot;wi[tot]=w;}
void solve(int u,int v,int w)
{
    int tot=0,pre=1;
    for(int i=v;i!=fa[u];i=fa[i])
    {
        vis[i]=i;
        s[i]=pre;pre++;a[i]=b[i];f[i]=++cnt;rev[cnt]=i;
    }
    s[n+1]=s[u];a[u]=w;up=cnt;
}
void tarjan(int u,int p)
{
    dfn[u]=low[u]=++id;
    for(int i=head[u];i;i=nex[i])
    {
        int v=to[i];if(v==p) continue;
        if(!dfn[v])
        {
            fa[v]=u;b[v]=wi[i];
            tarjan(v,u);low[u]=min(low[u],low[v]);
        }
        else low[u]=min(low[u],low[v]);
    }
    for(int i=head[u];i;i=nex[i])
    {
        int v=to[i];
        if(fa[v]!=u&&dfn[v]>dfn[u])
            solve(u,v,wi[i]);
    }
}
void dfs1(int u,int p)
{
    si[u]=1;fa[u]=p;dep[u]=dep[p]+1;ff[u][0]=p;
    for(int i=1;1<si[son[u]]) son[u]=v;
    }
}
void dfs2(int u)
{
    Id[u]=++cnt;rev[cnt]=u;
    if(son[u]) top[son[u]]=top[u],vis[son[u]]=vis[u],dfs2(son[u]);
    for(int i=head[u];i;i=nex[i])
    {
        int v=to[i];if(v==son[u]||v==fa[u]||vis[v]) continue;
        vis[v]=vis[u];
        top[v]=v;dfs2(v);
    }
}
int LCA(int u,int v)
{
    if(dep[u]dep[v]) u=ff[u][lg[dep[u]-dep[v]]-1];
    if(u==v) return u;
    for(int i=lg[dep[u]]-1;i>=0;i--)
        if(ff[u][i]!=ff[v][i])
        u=ff[u][i],v=ff[v][i];
    x=u;y=v;
    return ff[u][0];
}
struct node
{
    int lmx,lmn,rmx,rmn,mn,mx,sum;
    node(){lmx=lmn=rmx=rmn=mn=mx=sum=0;}
}t[N<<1][2];
int lz[N<<1];
node Merge(node a,node b)
{
    node ans;
    ans.sum=a.sum+b.sum;
    ans.lmn=min(a.lmn,a.sum+b.lmn);
    ans.lmx=max(a.lmx,a.sum+b.lmx);
    ans.rmn=min(b.rmn,b.sum+a.rmn);
    ans.rmx=max(b.rmx,b.sum+a.rmx);
    ans.mn=min(min(a.mn,b.mn),min(a.rmn+b.lmn,min(ans.lmn,ans.rmn)));
    ans.mx=max(max(a.mx,b.mx),max(a.rmx+b.lmx,max(ans.lmx,ans.rmx)));
    return ans;
}
void build(int l,int r,int k)
{
    if(l==r)
    {
        t[k][0]=node();
        t[k][0].lmn=t[k][0].lmx=t[k][0].rmn=t[k][0].rmx=t[k][0].sum=a[rev[l]];
        t[k][0].mx=t[k][0].sum;
        t[k][0].mn=t[k][0].sum;
        t[k][1]=t[k][0];
        return;
    }
    int m=l+r>>1;
    build(l,m,k<<1);build(m+1,r,k<<1|1);
    t[k][0]=Merge(t[k<<1][0],t[k<<1|1][0]);
    t[k][1]=Merge(t[k<<1|1][1],t[k<<1][1]);
}
void update(int l,int r,int k)
{
    t[k][0].lmn*=-1;t[k][0].lmx*=-1;t[k][0].rmn*=-1;t[k][0].rmx*=-1;t[k][0].mx*=-1;t[k][0].mn*=-1;t[k][0].sum*=-1;
    swap(t[k][0].mn,t[k][0].mx);swap(t[k][0].lmn,t[k][0].lmx);swap(t[k][0].rmn,t[k][0].rmx);
    t[k][1].lmn*=-1;t[k][1].lmx*=-1;t[k][1].rmn*=-1;t[k][1].rmx*=-1;t[k][1].mx*=-1;t[k][1].mn*=-1;t[k][1].sum*=-1;
    swap(t[k][1].mn,t[k][1].mx);swap(t[k][1].lmn,t[k][1].lmx);swap(t[k][1].rmn,t[k][1].rmx);
    if(l!=r)
        lz[k<<1]^=1,lz[k<<1|1]^=1;
    lz[k]^=1;
}
void fix(int l,int r,int k,int x,int y)
{
    if(lz[k]) update(l,r,k);
    if(ry) return;
    if(l>=x&&r<=y){lz[k]^=1;update(l,r,k);return;}
    int m=l+r>>1;
    fix(l,m,k<<1,x,y);fix(m+1,r,k<<1|1,x,y);
    t[k][0]=Merge(t[k<<1][0],t[k<<1|1][0]);
    t[k][1]=Merge(t[k<<1|1][1],t[k<<1][1]);
}
node query(int l,int r,int k,int x,int y,int opt)
{
    if(lz[k]) update(l,r,k);
    if(ry) return node();
    if(l>=x&&r<=y) return t[k][opt];
    int m=l+r>>1;
    return opt?Merge(query(m+1,r,k<<1|1,x,y,opt),query(l,m,k<<1,x,y,opt)):Merge(query(l,m,k<<1,x,y,opt),query(m+1,r,k<<1|1,x,y,opt));
}
int Q(int u,int v)
{
    if(vis[u]==vis[v])
    {
        int lca=LCA(u,v);
        node ansu=node(),ansv=node();
        while(top[u]!=top[lca])
            ansu=Merge(query(1,cnt,1,Id[top[u]],Id[u],0),ansu),u=fa[top[u]];
        if(u!=lca) ansu=Merge(query(1,cnt,1,Id[lca]+1,Id[u],0),ansu);
        while(top[v]!=top[lca])
            ansv=Merge(ansv,query(1,cnt,1,Id[top[v]],Id[v],1)),v=fa[top[v]];
        if(v!=lca) ansv=Merge(ansv,query(1,cnt,1,Id[lca]+1,Id[v],1)),v=fa[top[v]];
        return max(Merge(ansv,ansu).mx,0);
    }
    else
    {
        node ansu=node(),ansv=node(),ans;
        while(top[u]!=top[vis[u]])
            ansu=Merge(query(1,cnt,1,Id[top[u]],Id[u],0),ansu),u=fa[top[u]];
        ansu=Merge(query(1,cnt,1,Id[top[u]],Id[u],0),ansu);
        while(top[v]!=top[vis[v]])
            ansv=Merge(ansv,query(1,cnt,1,Id[top[v]],Id[v],1)),v=fa[top[v]];
        ansv=Merge(ansv,query(1,cnt,1,Id[top[v]],Id[v],1));
        u=vis[u];v=vis[v];
        if(s[u]dep[top[v]])
                fix(1,cnt,1,Id[top[u]],Id[u]),u=fa[top[u]];
            else fix(1,cnt,1,Id[top[v]],Id[v]),v=fa[top[v]];
        }
        if(dep[u]>dep[v]) fix(1,cnt,1,Id[v],Id[u]);
        fix(1,cnt,1,Id[u],Id[v]);
        fix(1,cnt,1,Id[lca],Id[lca]);
    }
    else
    {
        while(top[u]!=top[vis[u]])
            fix(1,cnt,1,Id[top[u]],Id[u]),u=fa[top[u]];
        fix(1,cnt,1,Id[top[u]],Id[u]);
        while(top[v]!=top[vis[v]])
            fix(1,cnt,1,Id[top[v]],Id[v]),v=fa[top[v]];
        fix(1,cnt,1,Id[top[v]],Id[v]);
        u=vis[u];v=vis[v];
        if(f[u]

你可能感兴趣的:(codechef Queries on tree again!)