P1545 Dividing the Path G(线段树+动态规划)
P1545 Dividing the Path G(线段树+动态规划)
题意简化
使用长度为 \([2A,2B]\) 的区间覆盖长度为 \(L\) 的线段,并给出 \(n\) 个子区间,要求每个子区间仅被同一区间覆盖,求最小的区间使用数量
思路
考虑 \(dp_i\) 表示覆盖 \([0,L]\) 范围的最小使用数量,一条右端点在 \(i\) 处的线段左端点范围为 \([i-2A,i-2B]\) ,我们可以在该范围内找出最小的 \(dp\) 值用于更新 \(dp_i\) ,使用线段树维护区间内最小的 \(dp\) 值
Code
//dp[i]=min(dp[j])+1,j->[i-2b,i-2a]
#include<iostream>
#define IOS ios::sync_with_stdio(false),cin.tie(0),cout.tie(0)
using namespace std;
const int N=1e6+5;
struct SegmentTree
{
struct node
{
int l,r,data;
}Tree[N<<2];
int lazy[N<<2];
void pushup(int k)
{
Tree[k].data=min(Tree[k<<1].data,Tree[k<<1|1].data);
}
void pushdown(int k)
{
if(!lazy[k]) return;
lazy[k<<1]=lazy[k];
Tree[k<<1].data=lazy[k];
lazy[k<<1|1]=lazy[k];
Tree[k<<1|1].data=lazy[k];
lazy[k]=0;
}
void buildtree(int k,int L,int R)
{
Tree[k].l=L,Tree[k].r=R;
if(L==R)
{
Tree[k].data=0x3f3f3f3f;
return;
}
int Mid=(L+R)>>1;
buildtree(k<<1,L,Mid);
buildtree(k<<1|1,Mid+1,R);
pushup(k);
}
void modify(int k,int L,int R,int val)
{
if(L<=Tree[k].l&&Tree[k].r<=R)
{
Tree[k].data=val;
lazy[k]=val;
return;
}
pushdown(k);
if(L<=Tree[k<<1].r)
modify(k<<1,L,R,val);
if(R>=Tree[k<<1|1].l)
modify(k<<1|1,L,R,val);
pushup(k);
}
int query(int k,int L,int R)
{
if(L<=Tree[k].l&&Tree[k].r<=R)
return Tree[k].data;
pushdown(k);
int res=0x3f3f3f3f;
if(L<=Tree[k<<1].r)
res=min(res,query(k<<1,L,R));
if(R>=Tree[k<<1|1].l)
res=min(res,query(k<<1|1,L,R));
return res;
}
}Segment;
bool vis[N];
int n,len,A,B,dp[N];
int main()
{
IOS;
cin>>n>>len>>A>>B;
Segment.buildtree(1,0,len);
Segment.modify(1,0,0,0);//dp[0]赋初始值为0
for(int i=1;i<=n;i++)
{
int st,ed;
cin>>st>>ed;
for(int j=st+1;j<=ed-1;j++)
vis[j]=true;
}
for(int i=2*A;i<=len;i+=2)
{
if(vis[i]) continue;
int L=max(0,i-2*B),R=i-2*A,tmp=Segment.query(1,L,R);//注意边界问题
dp[i]=tmp+1,Segment.modify(1,i,i,dp[i]);//每次求得dp[i]后更新线段树中的值
}
cout<<(dp[len]>=0x3f3f3f3f?-1:dp[len])<<'\n';
return 0;
}
完结撒花~
浙公网安备 33010602011771号