Description

相信大家都在长训班学过树塔问题,题目很简单求最大化一个三角形数塔从上往下走的路径和。走的规则是:(i,j)号点只能走向(i+1,j)或者(i+1,j+1)。如下图是一个数塔,映射到该数塔上行走的规则为:从左上角的点开始,向下走或向右下走直到最底层结束。

1
3 8
2 5 0
1 4 3 8
1 4 2 5 0

路径最大和是1+8+5+4+4 = 22,1+8+5+3+5 = 22或者1+8+0+8+5 = 22。

小S觉得这个问题so easy。于是他提高了点难度,他每次ban掉一个点(即规定哪个点不能经过),然后询问你不走该点的最大路径和。
当然他上一个询问被ban掉的点过一个询问会恢复(即每次他在原图的基础上ban掉一个点,而不是永久化的修改)。

Solution

看起来很简单,实际上也很简单。
用f[i][j]表示顶点到这个点的最长路,g[i][j]表示这个点到底层的最短路。
如果一个点被ban了,那么要让这个点不受影响,那么只能用这一层的点的f[i][j]+g[i][j]-a[i][j]的max值,同层的点实绝对不会经过的。
其实n2预处理就可以了。但是我用了线段树,能过就行了。

Code

#include<cstdio>
#include<iostream>
#include<algorithm>
#include<cmath>
#include<cstring>
#define fo(i,a,b) for(i=a;i<=b;i++)
#define fod(i,a,b) for(i=a;i>=b;i--)
using namespace std;
const int maxn=1007;
int i,j,k,l,n,m,ans,x,y,ans1,ans2;
int a[maxn][maxn],f[maxn][maxn],g[maxn][maxn];
int t[500007*4],b[1000007];
void build(int x,int l,int r){
if(l==r){
t[x]=b[l];
return;
}
int mid=(l+r)/2;
build(x*2,l,mid);
build(x*2+1,mid+1,r);
t[x]=max(t[x*2],t[x*2+1]);
}
int find(int x,int l,int r,int y,int z){
if(y>z)return 0;
if(l==y&&r==z){
return t[x];
}
int mid=(l+r)/2;
if(z<=mid)return find(x*2,l,mid,y,z);
else if(y>mid)return find(x*2+1,mid+1,r,y,z);
else{
return max(find(x*2,l,mid,y,mid),find(x*2+1,mid+1,r,mid+1,z));
}
}
int read(){
int x=0;
char ch=getchar();
while(ch>'9'||ch<'0')ch=getchar();
while(ch<='9'&&ch>='0')x=x*10+ch-'0',ch=getchar();
return x;
}
int main(){
// freopen("fan.in","r",stdin);
// freopen("fan.out","w",stdout);
n=read(),m=read();
fo(i,1,n){
fo(j,1,i){
a[i][j]=read();
}
}
fo(i,1,n){
fo(j,1,i){
f[i][j]=max(f[i][j],f[i-1][j-1]+a[i][j]);
f[i][j]=max(f[i][j],f[i-1][j]+a[i][j]);
}
}
fo(i,1,n)g[n][i]=a[n][i],ans1=max(ans1,f[n][i]);
fod(i,n-1,1){
fo(j,1,i){
g[i][j]=max(g[i][j],g[i+1][j+1]+a[i][j]);
g[i][j]=max(g[i][j],g[i+1][j]+a[i][j]);
}
}
fo(i,1,n)fo(j,1,i)b[++b[0]]=f[i][j]+g[i][j]-a[i][j];
build(1,1,b[0]);
while(m--){
x=read(),y=read();
if(x==1&&y==1)printf("-1\n");
else{
ans=0;
int u=(1+(x-1))*(x-1)/2+1,v=(1+x)*x/2,now=u-1+y;
ans=max(ans,find(1,1,b[0],u,now-1));
ans=max(ans,find(1,1,b[0],now+1,v));
printf("%d\n",ans);
}
}
}