[SDOI2015]道路修建

不知道为什么之前这篇在博客园上出了一点问题

链接

P5618


题解

线段树之什么都能维护

用线段树维护最小生成树。

和[SHOI2008]堵塞的交通很像,一开始想naive了,以为只需要维护上下联通和不联通的答案,两个联通的合并加上中间小的边。

但是这样其实假掉了,一组hack是

7 1
2 5 9 4 7 2 
2 10 8 7 7 6 
8 2 3 10 7 6 8 
Q 1 7

答案应该是 61,而不是 63。

把图画出来后发现其实两个联通的合并的时候中间形成了个环,应该从环上减掉最大的,而不能只看中间连接的两条边。

为了处理这个环,我们需要维护此时一段区间最左/右的竖边及其左/右边的边权最大值。

然后还有一个问题是如果左/右边只有一条竖边并且被减掉了,那么更新的时候就需要用另一边的信息。为了处理这个问题,需要记录最左/右的竖边权值和区间内竖边总数,以及区间内所有横边的最大值。

于是我们就可以处理掉这个pushup了

inline void pushup(node &p,node x,node y){
	p.L=x.L,p.R=y.R;int mid=x.R,tt=max(uc[mid],dc[mid]);
	p.maxn=max(tt,max(x.maxn,y.maxn));
	int t1=max(tt,max(x.maxrr,y.minll)),t=x.con+y.con+uc[mid]+dc[mid]-t1;
	p.con=t,p.sum=x.sum+y.sum-1;
	p.minl=x.minl,p.minll=x.minll,p.maxr=y.maxr,p.maxrr=y.maxrr;
	if(t1!=x.maxr&&t1!=y.minl)p.sum++;
	if(t1==x.maxr&&x.sum==1)p.minl=y.minl,p.minll=max(tt,max(y.minll,x.maxn));
	else if(t1==y.minl&&y.sum==1)p.maxr=x.maxr,p.maxrr=max(tt,max(x.maxrr,y.maxn));
}

然后修改就和[SHOI2008]堵塞的交通一样,查询答案还要简单一些。

然后就做完了。


code

#include<bits/stdc++.h>
using namespace std;
#define int long long
#define cs const
#define in read()
inline int read(){
	int p=0,f=1;char c=getchar();
	while(!isdigit(c)){if(c=='-')f=-1;c=getchar();}
	while(isdigit(c)){p=p*10+c-48;c=getchar();}
	return p*f;
}
cs int N=60005;
int n,m;
int uc[N],dc[N],c[N];
struct node{
	int con,sum,maxr,minl,maxrr,minll,maxn;
	int L,R;
}a[N<<2];
inline void pushup(node &p,node x,node y){
	p.L=x.L,p.R=y.R;int mid=x.R,tt=max(uc[mid],dc[mid]);
	p.maxn=max(tt,max(x.maxn,y.maxn));
	int t1=max(tt,max(x.maxrr,y.minll)),t=x.con+y.con+uc[mid]+dc[mid]-t1;
	p.con=t,p.sum=x.sum+y.sum-1;
	p.minl=x.minl,p.minll=x.minll,p.maxr=y.maxr,p.maxrr=y.maxrr;
	if(t1!=x.maxr&&t1!=y.minl)p.sum++;
	if(t1==x.maxr&&x.sum==1)p.minl=y.minl,p.minll=max(tt,max(y.minll,x.maxn));
	else if(t1==y.minl&&y.sum==1)p.maxr=x.maxr,p.maxrr=max(tt,max(x.maxrr,y.maxn));
}
inline void built(int l,int r,int p){
	if(l==r){a[p].sum=1,a[p].maxn=0,a[p].con=a[p].maxr=a[p].minl=a[p].minll=a[p].maxrr=c[l],a[p].L=a[p].R=l;return ;}
	int mid=(l+r)>>1;built(l,mid,p<<1),built(mid+1,r,p<<1|1),pushup(a[p],a[p<<1],a[p<<1|1]);
}
inline void change1(int l,int r,int p,int x,int d){
	int mid=(l+r)>>1;
	if(l==r){a[p].con=a[p].maxr=a[p].minl=a[p].minll=a[p].maxrr=d;return ;}
	if(x<=mid)change1(l,mid,p<<1,x,d);
	else change1(mid+1,r,p<<1|1,x,d);
	pushup(a[p],a[p<<1],a[p<<1|1]);
}
inline void change2(int l,int r,int p,int x,int ud,int d){
	int mid=(l+r)>>1;
	if(mid==x){
		if(ud)uc[x]=d;
		else dc[x]=d;
		pushup(a[p],a[p<<1],a[p<<1|1]);
		return ;
	}
	if(x<mid)change2(l,mid,p<<1,x,ud,d);
	else change2(mid+1,r,p<<1|1,x,ud,d);
	pushup(a[p],a[p<<1],a[p<<1|1]);
}
inline node query(int l,int r,int p,int ql,int qr){
	if(l>=ql&&r<=qr)return a[p];
	int mid=(l+r)>>1;
	if(qr<=mid)return query(l,mid,p<<1,ql,qr);
	if(ql>mid)return query(mid+1,r,p<<1|1,ql,qr);
	node ans;pushup(ans,query(l,mid,p<<1,ql,qr),query(mid+1,r,p<<1|1,ql,qr));
	return ans;
}
string s;
int r1,c1,r2,c2,d;
signed main(){
	n=in,m=in;
	for(int i=1;i<n;i++)uc[i]=in;
	for(int i=1;i<n;i++)dc[i]=in;
	for(int i=1;i<=n;i++)c[i]=in;
	built(1,n,1);
	for(int i=1;i<=m;i++){
		cin>>s;
		if(s[0]=='C'){
			r1=in,c1=in,r2=in,c2=in,d=in;
			if(c1>c2)swap(c1,c2),swap(r1,r2);
			if(r1==r2)change2(1,n,1,c1,r1==1,d);
			else change1(1,n,1,c1,d);
		}
		else{
			c1=in,c2=in;
			cout<<query(1,n,1,c1,c2).con<<'\n';
		}
	}
	return 0;
}
posted @ 2022-03-24 07:56  llmmkk  阅读(54)  评论(0编辑  收藏  举报