题解 CF515E 【Drazil and Park】
Farkas_W
·
·
题解
思路:
```cpp
struct node{
int suml,sumr,Max;
}t[N<<2];
il void build(int k,int l,int r)
{
if(l==r){t[k].suml=h[l]+dis[l];t[k].sumr=h[l]-dis[l];t[k].Max=-inf;return;}//suml表示作右端点,sumr表示作左端点
int mid=l+r>>1;
build(k<<1,l,mid);build(k<<1|1,mid+1,r);
t[k].suml=max(t[k<<1].suml,t[k<<1|1].suml);
t[k].sumr=max(t[k<<1].sumr,t[k<<1|1].sumr);
t[k].Max=max(t[k<<1].Max,max(t[k<<1|1].Max,t[k<<1|1].suml+t[k<<1].sumr));//取 (左儿子的最大值,右儿子的最大值,左儿子中最适合作左端点的加上右儿子中最适合作右端点的和) 这三者的最大值
}
il node query(int k,int l,int r,int x,int y)
{
if(x<=l&&y>=r)return t[k];
int mid=l+r>>1;node t1,t2,t3;
t1.suml=t1.sumr=t1.Max=t2.suml=t2.sumr=t2.Max=t3.suml=t3.sumr=t3.Max=-inf;
if(x<=mid)t1=query(k<<1,l,mid,x,y);
if(y>mid)t2=query(k<<1|1,mid+1,r,x,y);
t3.suml=max(t1.suml,t2.suml);
t3.sumr=max(t1.sumr,t2.sumr);
t3.Max=max(t1.Max,max(t2.Max,t2.suml+t1.sumr));
return t3;
}
```
$\quad$关于变量名的解释:用数组 $h_i$ 表示第 $i$ 棵树的高度(或 $i-n$ ),数组 $d_i$ 表示第 $i$ 棵树和第 $i+1$ 棵树的距离,数组 $dis_i$ 表示第 $i$ 棵树的坐标, $sumr$ 指最大的可做左端点的数, $suml$ 指最大的可做右端点的数, $Max$ 指这个区间的最大答案
$\quad$再看看主函数吧,求补集的操作要额外注意
```cpp
signed main()
{
n=read();m=read();
for(re i=1;i<=n;i++)d[i]=d[i+n]=read();
for(re i=1;i<=n;i++)h[i]=h[i+n]=read()<<1;
for(re i=1;i<=n<<1;i++)dis[i]=dis[i-1]+d[i-1];//注意d[i-1]表示的才是第i-1棵树与第i棵树的距离
build(1,1,n<<1);//建树
while(m--)
{
re x=read(),y=read();
if(y<x){swap(x,y);x++;y--;} //这个求补集的操作也要额外注意
else {swap(x,y);x++;y=y+n-1;}//这个求补集的操作也要额外注意
print(query(1,1,n<<1,x,y).Max);putchar('\n');
}
return 0;
}
```