BZOJ2104【线段树】

很详细的题解:http://blog.csdn.net/iamzky/article/details/42119193

要注意信息合并时.下标的先后顺序.很容易出错.

/* I will wait for you */
 
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<iostream>
#include<fstream>
#include<vector>
#include<queue>
#include<deque>
#include<set>
#include<map>
#include<string>
#define make(a,b) make_pair(a,b)
#define fi first
#define se second
 
using namespace std;
 
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
 
const int maxn=100010;
const int maxm=100010;
const int maxs=6;
const int INF=0x3f3f3f3f;
const int P=1000000007;
const double error=1e-4;

inline int read()
{
	int x=0,f=1;char c=getchar();
	while(c>'9'||c<'0') f=(c=='-'?-1:1),c=getchar();
	while(c<='9'&&c>='0') (x*=10)+=c-'0',c=getchar();
	return x*f;
}

struct node
{
	int ll[6][6],lr[6][6],rr[6][6];
	
	inline void clear()
	{
		memset(ll,0x3f,sizeof(ll));
		memset(lr,0x3f,sizeof(lr));
		memset(rr,0x3f,sizeof(rr));
	}
	
	inline bool empty()
	{
		return ll[1][1]==INF;
	}
}e[4*maxn];

inline node operator + (node li,node ri)
{
	node ans;ans.clear();
	
	if(li.empty()) return ri;
	if(ri.empty()) return li;
	
	int lm[6][6],rm[6][6];
	memset(lm,0x3f,sizeof(lm));
	memset(rm,0x3f,sizeof(rm));
	
	for(int k=0;k<6;k++) for(int i=0;i<6;i++) for(int j=0;j<6;j++)
	{
		lm[i][j]=min(lm[i][j],li.lr[i][k]+ri.ll[k][j]);
		rm[i][j]=min(rm[i][j],li.rr[j][k]+ri.lr[k][i]);
	}
	
	for(int i=0;i<6;i++) for(int j=0;j<6;j++)
	{
		ans.ll[i][j]=li.ll[i][j],ans.rr[i][j]=ri.rr[i][j];
		for(int k=0;k<6;k++)
		{
			ans.ll[i][j]=min(ans.ll[i][j],lm[i][k]+li.lr[j][k]);
			ans.rr[i][j]=min(ans.rr[i][j],rm[i][k]+ri.lr[k][j]);
			ans.lr[i][j]=min(ans.lr[i][j],li.lr[i][k]+ri.lr[k][j]);
			ans.lr[i][j]=min(ans.lr[i][j],lm[i][k]+rm[j][k]);
		}
	}
	return ans;
}	

int n,m,wi[maxn][6],sum[6];

inline node init(int y)
{
	node ans;ans.clear();
	
	for(int i=0;i<6;i++) ans.ll[i][i]=ans.lr[i][i]=ans.rr[i][i]=wi[y][i];
	
	for(int i=0;i<6;i++) sum[i]=sum[i-1]+wi[y][i];
	
	for(int i=0;i<6;i++) for(int j=0;j<6;j++)
		ans.ll[i][j]=ans.lr[i][j]=ans.rr[i][j]=sum[max(i,j)]-sum[min(i,j)-1];
	
	return ans;
}

inline void build(int o,int l,int r)
{
	if(l==r) e[o]=init(l);
	else
	{
		int mid=(l+r)/2;
		build(2*o,l,mid),build(2*o+1,mid+1,r);
		e[o]=e[2*o]+e[2*o+1];
	}
}

inline void change(int o,int l,int r,int c)
{
	if(l==r) e[o]=init(l);
	else
	{
		int mid=(l+r)/2;
		c<=mid?change(2*o,l,mid,c):change(2*o+1,mid+1,r,c);
		e[o]=e[2*o]+e[2*o+1];
	}
}

inline node qmin(int o,int l,int r,int x,int y)
{
	node ans;ans.clear();
	if(l>=x&&r<=y) ans=e[o];
	else
	{
		int mid=(l+r)/2;
		if(x<=mid) ans=qmin(2*o,l,mid,x,y)+ans;
		if(y>mid) ans=ans+qmin(2*o+1,mid+1,r,x,y);		
	}		
	return ans;
}
		
inline int query(int x1,int y1,int x2,int y2)
{
	node li=qmin(1,1,n,1,y1);
	node mi=qmin(1,1,n,y1,y2);
	node ri=qmin(1,1,n,y2,n);
	
	int ans=mi.lr[x1][x2];
	
	for(int i=0;i<6;i++) for(int j=0;j<6;j++)
	{
		ans=min(ans,mi.ll[x1][i]+li.rr[i][j]+mi.lr[j][x2]-wi[y1][i]-wi[y1][j]);
		ans=min(ans,mi.lr[x1][i]+ri.ll[i][j]+mi.rr[j][x2]-wi[y2][i]-wi[y2][j]);
		ans=min(ans,li.rr[x1][i]+mi.lr[i][j]+ri.ll[j][x2]-wi[y1][i]-wi[y2][j]);
	}
	
	return ans;
}
		
int main()
{
	n=read();	
	for(int i=0;i<6;i++) for(int j=1;j<=n;j++) wi[j][i]=read();
	build(1,1,n);	
	
	m=read();
	while(m--)
	{
		int t=read();
		if(t==1)
		{
			int x=read(),y=read(),z=read();
			wi[y][x-1]=z,change(1,1,n,y);
		}
		if(t==2)
		{
			int x1=read(),y1=read(),x2=read(),y2=read();
			if(y1>y2) swap(x1,x2),swap(y1,y2);
			printf("%d\n",query(x1-1,y1,x2-1,y2));
		}
	}
	
	return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值