在一个长条状的东西上维护信息,我们可以想到使用线段树。
对于一个对应范围为 [L,R] 的节点,我们维护区间内最左边的那一列的点的每一个点和最右边一列的每一个点两两之间只经过 [L,R] 的点的最短路。
关于合并,可以查看http://blog.csdn.net/iamzky/article/details/42119193
关于最后求答案呢。
我们求出1..l + l..r +r..n答案,记作 X Y Z
最终答案的构成可能有4种可能。
同样是因为只有6行。
然后就A了。
#include
#include
#define INF 0x7fffffffffffffffll
#define MAXN 100000
using namespace std;
template<class T>
void Read(T &x){
char c;
bool f(0);
while(c=getchar(),c!=EOF)
if(c=='-')
f=1;
else if(c>='0'&&c<='9'){
x=c-'0';
while(c=getchar(),c>='0'&&c<='9')
x=x*10+c-'0';
ungetc(c,stdin);
if(f)
x=-x;
return;
}
}
typedef long long LL;
int n,m,a[6][MAXN+10];
void read(){
Read(n);
int i,j;
for(i=0;i<6;i++)
for(j=1;j<=n;j++)
Read(a[i][j]);
}
struct node{
LL ll[6][6],lr[6][6],rr[6][6];
bool empty;
inline node(){
}
inline node(bool empty):empty(empty){
}
inline bool operator == (const node &b)const{
int i,j;
for(i=0;i<6;i++)
for(j=0;j<6;j++)
if(ll[i][j]!=b.ll[i][j]||lr[i][j]!=b.lr[i][j]||rr[i][j]!=b.rr[i][j])
return 0;
return 1;
}
}tree[(1<<18)+10];
inline node merge(const node &a,const node &b){
if(a.empty)
return b;
if(b.empty)
return a;
static LL lm[6][6],rm[6][6];
node ret(0);
int i,j,k;
for(i=0;i<6;i++)
for(j=0;j<6;j++){
lm[i][j]=rm[i][j]=ret.lr[i][j]=INF;
ret.ll[i][j]=a.ll[i][j],ret.rr[i][j]=b.rr[i][j];
}
for(k=0;k<6;k++)
for(i=0;i<6;i++)
for(j=0;j<6;j++){
lm[i][j]=min(lm[i][j],a.lr[i][k]+b.ll[k][j]);
rm[i][j]=min(rm[i][j],a.rr[i][k]+b.lr[k][j]);
}
for(k=0;k<6;k++)
for(i=0;i<6;i++)
for(j=0;j<6;j++){
ret.ll[i][j]=min(ret.ll[i][j],lm[i][k]+a.lr[j][k]);
ret.rr[i][j]=min(ret.rr[i][j],rm[k][i]+b.lr[k][j]);
ret.lr[i][j]=min(ret.lr[i][j],min(a.lr[i][k]+b.lr[k][j],lm[i][k]+rm[k][j]));
}
return ret;
}
void cal(node &b,int l){
static LL sum[6];
int i,j;
sum[0]=a[0][l];
for(j=1;j<6;j++)
sum[j]=sum[j-1]+a[j][l];
for(i=0;i<6;i++)
for(j=0;j<6;j++)
b.ll[i][j]=b.lr[i][j]=b.rr[i][j]=i>j?sum[i]-(j?sum[j-1]:0):sum[j]-(i?sum[i-1]:0);
}
void build(int i,int l,int r){
if(l==r){
cal(tree[i],l);
return;
}
int mid((l+r)>>1);
build(i<<1,l,mid);
build((i<<1)|1,mid+1,r);
tree[i]=merge(tree[i<<1],tree[(i<<1)|1]);
}
bool insert(int i,int l,int r,int p){
if(l==r){
cal(tree[i],l);
return 1;
}
int mid((l+r)>>1);
bool f;
if(p<=mid)
f=insert(i<<1,l,mid,p);
else
f=insert((i<<1)|1,mid+1,r,p);
if(f){
node t=merge(tree[i<<1],tree[(i<<1)|1]);
if(tree[i]==t)
return 0;
else{
tree[i]=t;
return 1;
}
}
return 0;
}
inline node get_sum(int i,int l,int r,int ll,int rr){
if(ll<=l&&r<=rr)
return tree[i];
if(ll>r||rrreturn 1;
int mid((l+r)>>1);
return merge(get_sum(i<<1,l,mid,ll,rr),get_sum((i<<1)|1,mid+1,r,ll,rr));
}
inline LL Query(LL x1,LL y1,LL x2,LL y2){
node x=get_sum(1,1,n,1,y1),y=get_sum(1,1,n,y1,y2),z=get_sum(1,1,n,y2,n);
int i,j,k;
static LL lr[6][6],rl[6][6],ans;
for(i=0;i<6;i++)
for(j=0;j<6;j++)
lr[i][j]=rl[i][j]=y.lr[i][j];
for(k=0;k<6;k++)
for(i=0;i<6;i++)
for(j=0;j<6;j++){
lr[i][j]=min(lr[i][j],y.lr[i][k]+z.ll[k][j]-a[k][y2]);
rl[i][j]=min(rl[i][j],x.rr[i][k]+y.lr[k][j]-a[k][y1]);
}
ans=y.lr[x1][x2];
for(i=0;i<6;i++)
for(j=0;j<6;j++){
ans=min(ans,y.ll[x1][i]+x.rr[i][j]+y.lr[j][x2]-a[i][y1]-a[j][y1]);
ans=min(ans,y.lr[x1][i]+z.ll[i][j]+y.rr[j][x2]-a[i][y2]-a[j][y2]);
ans=min(ans,x.rr[x1][i]+y.lr[i][j]+z.ll[j][x2]-a[i][y1]-a[j][y2]);
ans=min(ans,lr[x1][i]+y.lr[j][i]+rl[j][x2]-a[i][y2]-a[j][y1]);
}
return ans;
}
void solve(){
build(1,1,n);
int p,x,y,x2,y2;
Read(m);
while(m--){
Read(p);
if(p==1){
Read(x),Read(y),Read(a[x-1][y]);
insert(1,1,n,y);
}
else{
Read(x),Read(y),Read(x2),Read(y2);
if(y>y2)
swap(x,x2),swap(y,y2);
printf("%lld\n",Query(x-1,y,x2-1,y2));
}
}
}
int main()
{
read();
solve();
}