一开始以为是个仙人掌,于是拿圆方树写,然后发现边上的权值用圆方树很难维护。但是注意到只有一个环,所以就分两种情况进行树链剖分。把环上的每一个点都看作一颗树根,然后分两种情况剖分。
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]