题解 [IOI2008]Pyramid Base 金字塔地基
题目链接
题意描述
你有一片
的网格,其中有 个障碍 ,并有一个移除的费用 ,你有 的预算用于移除障碍,求修建一座正方形金字塔的最大边长。
三组
两类
既然没有预算,那么就可以直接将障碍扫描线,对于
点击查看代码
namespace Subtask1{
vector<int>Line[M][2];
namespace SGT{
struct Data{int lmax,rmax,Max,Len,Tag,Add;}tr[M<<2];
void Pushup(int k){
if(tr[k].Add>=1)return void(tr[k].lmax=tr[k].rmax=tr[k].Max=0);
if(tr[k].Len==1)return void(tr[k].lmax=tr[k].rmax=tr[k].Max=1);
tr[k].Len=tr[ls].Len+tr[rs].Len;
tr[k].lmax=(tr[ls].lmax==tr[ls].Len)?tr[ls].Len+tr[rs].lmax:tr[ls].lmax;
tr[k].rmax=(tr[rs].rmax==tr[rs].Len)?tr[rs].Len+tr[ls].rmax:tr[rs].rmax;
tr[k].Max=max(tr[ls].rmax+tr[rs].lmax,max(tr[ls].Max,tr[rs].Max));
}
void Build(int k,int l,int r){
if(l==r){
tr[k].lmax=tr[k].rmax=tr[k].Max=tr[k].Len=1;
return;
}
Build(ls,l,mid);
Build(rs,mid+1,r);
Pushup(k);
}
void Modify(int k,int l,int r,int x,int y,int z){
if(l>=x&&r<=y){
tr[k].Add+=z;
Pushup(k);
return;
}
if(x<=mid)Modify(ls,l,mid,x,y,z);
if(mid<y)Modify(rs,mid+1,r,x,y,z);
Pushup(k);
}
}
using namespace SGT;
void Solve(){
Build(1,1,m);
for(int i=1;i<=P;i++)Line[a[i].x[0]][0].pb(i),Line[a[i].x[1]][1].pb(i);
for(int i=1,j=0;i<=n;i++){
while(tr[1].Max>j-i&&j<=n){
j++;
for(auto k:Line[j][0])
Modify(1,1,m,a[k].y[0],a[k].y[1],1);
}
ans=max(ans,j-i);
for(auto k:Line[i][1])
Modify(1,1,m,a[k].y[0],a[k].y[1],-1);
}
printf("%d\n",ans);
}
}
上来显然先二分答案
一个障碍对正方形的影响范围为
点击查看代码
namespace Subtask2{
Obstacle b[N];
vector<int>Line[M][2];
namespace SGT{
struct Data{int Min,Tag;}tr[M<<2];
void Pushup(int k){tr[k].Min=min(tr[ls].Min,tr[rs].Min);}
void Update(int k,int v){tr[k].Tag+=v;tr[k].Min+=v;}
void Pushdown(int k){
if(tr[k].Tag!=0){
Update(ls,tr[k].Tag);
Update(rs,tr[k].Tag);
tr[k].Tag=0;
}
}
void Build(int k,int l,int r){
tr[k].Min=tr[k].Tag=0;
if(l==r)return;
Build(ls,l,mid);
Build(rs,mid+1,r);
}
void Modify(int k,int l,int r,int x,int y,int z){
if(l>=x&&r<=y){
Update(k,z);
return;
}
Pushdown(k);
if(x<=mid)Modify(ls,l,mid,x,y,z);
if(mid<y)Modify(rs,mid+1,r,x,y,z);
Pushup(k);
}
}
using namespace SGT;
bool check(int x){
Build(1,1,m-x+1);
for(int i=1;i<=n-x+1;i++)Line[i][0].clear(),Line[i][1].clear();
for(int i=1;i<=P;i++){
b[i]=a[i];
b[i].x[0]=max(b[i].x[0]-x+1,1);
b[i].y[0]=max(b[i].y[0]-x+1,1);
b[i].x[1]=min(b[i].x[1],n-x+1);
b[i].y[1]=min(b[i].y[1],m-x+1);
if(b[i].x[0]>b[i].x[1]||b[i].y[0]>b[i].y[1])continue;
Line[b[i].x[0]][0].pb(i);
Line[b[i].x[1]][1].pb(i);
}
for(int i=1;i<=n-x+1;i++){
for(auto j:Line[i][0])
Modify(1,1,m-x+1,b[j].y[0],b[j].y[1],b[j].C);
if(tr[1].Min<=B)return true;
for(auto j:Line[i][1])
Modify(1,1,m-x+1,b[j].y[0],b[j].y[1],-b[j].C);
}
return false;
}
void Solve(){
int l=1,r=min(n,m),ans=0;
while(l<=r){
if(check(mid))ans=mid,l=mid+1;
else r=mid-1;
}
printf("%d\n",ans);
}
}
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】抖音旗下AI助手豆包,你的智能百科全书,全免费不限次数
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 分享一个免费、快速、无限量使用的满血 DeepSeek R1 模型,支持深度思考和联网搜索!
· 使用C#创建一个MCP客户端
· ollama系列1:轻松3步本地部署deepseek,普通电脑可用
· 基于 Docker 搭建 FRP 内网穿透开源项目(很简单哒)
· 按钮权限的设计及实现