传送门:bzoj3995
题解
设 [ l , r ] [l,r] [l,r]表示第 l − r l-r l−r列连通块的 M S T MST MST信息,考虑在线段树上合并两个区间:
连接 m i d → m i d + 1 mid\to mid+1 mid→mid+1上下的两条横线后,构成了一个以 [ l , m i d ] [l,mid] [l,mid]最右的一条竖线和 [ m i d + 1 , r ] [mid+1,r] [mid+1,r]最左一条竖线构成的环,需要删去环上边权最大的边。
于是线段树每个节点维护:
mx
\text{mx}
mx:区间横线最大值
ls,rs
\text{ls,rs}
ls,rs:区间最左/右的竖线位置
lmx,rmx
\text{lmx,rmx}
lmx,rmx:区间最左/右的竖线再向左/右的横线最大值
sum
\text{sum}
sum:区间
M
S
T
MST
MST总边权
为方便合并,我底层维护的是 [ l , l + 1 ] [l,l+1] [l,l+1]区间而非单个节点,所以每次分治的时候是 [ l , r ] → [ l , m i d ] , [ m i d , r ] [l,r]\to [l,mid],[mid,r] [l,r]→[l,mid],[mid,r]
p.s.
这里感觉上每次维护
m
x
=
(
l
.
m
x
,
r
.
m
x
)
mx=(l.mx,r.mx)
mx=(l.mx,r.mx)似乎有些问题(因为维护的是所有横线的最大权,而这个最大权可能已被删除),然而考虑什么情况下才需要调用这个
m
x
mx
mx:
当且仅当删了一条竖边,且这半部分不存在其它竖边时,
l
m
x
/
r
m
x
lmx/rmx
lmx/rmx变成了这半部分的
m
x
mx
mx和另外一半的
l
m
x
/
r
m
x
lmx/rmx
lmx/rmx取
max
\max
max的值,由因为这半部分只存在一条竖边,所以其它横线都存在,所以
m
x
mx
mx值是正确的。
代码
#include<bits/stdc++.h>
#define mid (l+r>>1)
#define lc k<<1
#define rc k<<1|1
#define lcc lc,l,mid
#define rcc rc,mid,r
typedef long long ll;
using namespace std;
const int N=120005;
int n,m;
int w[2][N],v[N];
char cp;
inline int init(){
for(;;){
cp=getchar();
if(cp=='Q') return 1;if(cp=='C') return 0;
}
}
struct node{
int ls,rs,lmx,rmx,mx;ll sum;
node operator +(node r){
node re;int mxx=max(rmx,r.lmx);
re.sum=sum+r.sum;re.mx=max(mx,r.mx);
re.ls=ls;re.rs=r.rs;
re.lmx=lmx;re.rmx=r.rmx;
if(mxx>max(v[rs],v[r.ls])) re.sum-=mxx;
else if(v[rs]>v[r.ls]){
re.sum-=v[rs];
if(ls==rs) re.ls=r.ls,re.lmx=max(mx,r.lmx);
}else{
re.sum-=v[r.ls];
if(r.ls==r.rs) re.rs=rs,re.rmx=max(rmx,r.mx);
}
return re;
}
}t[N<<2];
inline node mg(int l,int r)
{
node k;int x=max(v[l],v[r]),y=max(w[0][l],w[1][l]);
k.mx=y;k.sum=(ll)v[l]+v[r]+w[0][l]+w[1][l]-max(x,y);
if(x>y){
if(v[l]==x) k.ls=k.rs=r,k.lmx=y,k.rmx=0;
else k.ls=k.rs=l,k.rmx=y,k.lmx=0;
}else k.ls=l,k.rs=r,k.lmx=k.rmx=0;
return k;
}
void build(int k,int l,int r)
{
if(r-1==l){t[k]=mg(l,r);return;}
build(lcc);build(rcc);t[k]=t[lc]+t[rc];
}
void chg(int k,int l,int r,int L,int R)
{
if(r-l==1){t[k]=mg(l,r);return;}
if(L<=mid) chg(lcc,L,min(mid,R));
if(R>=mid) chg(rcc,max(L,mid),R);
t[k]=t[lc]+t[rc];
}
node ask(int k,int l,int r,int L,int R)
{
if(L==l && r==R) return t[k];
if(R<=mid) return ask(lcc,L,R);
if(L>=mid) return ask(rcc,L,R);
return (ask(lcc,L,mid)+ask(rcc,mid,R));
}
int main(){
int i,j,x,y,z;
scanf("%d%d",&n,&m);
for(j=0;j<2;++j)
for(i=1;i<n;++i) scanf("%d",&w[j][i]);
for(i=1;i<=n;++i) scanf("%d",&v[i]);
build(1,1,n);
for(;m;--m){
if(init()){
scanf("%d%d",&x,&y);
if(x==y) printf("%d\n",v[x]);else
printf("%lld\n",ask(1,1,n,x,y).sum);
}else{
scanf("%d%d%d%d%d",&x,&y,&i,&j,&z);if(y>j) swap(y,j);
if(y^j) w[x-1][y]=z;else v[y]=z;chg(1,1,n,y,j);
}
}
return 0;
}