题解:CF780G Andryusha and Nervous Barriers
题目链接:洛谷 Codeforces
既然没有 CDQ 分治的题解,那我就来水一篇。
思路
考虑确定从一个隔板边缘掉落会到哪个隔板上,以及从每个 \((h+1,i)\) 释放会到哪个隔板上。
首先,如果没有穿过隔板的限制,一个简单的做法就是按 \(h\) 轴从小到大做扫描线,用线段树等数据结构维护 \(w\) 轴每个位置当前在最上面的隔板编号。
再考虑加上穿过隔板的限制。设当前询问从 \((x,y)\) 会落到哪个隔板上,这个限制就相当于要求 \(x\leq u_i+s_i\)。这可以 CDQ 分治,设每个隔板的权值为 \(u_i+s_i\),每个询问的权值为 \(x\),将所有隔板和询问按权值降序排序(如果有相同的权值则隔板靠前。),则只有左边的隔板能作为右边询问的答案,然后就是公式化的 CDQ 分治,在每个分治层对左边的隔板和右边的询问做上述扫描线即可。
确定了从一个隔板会掉到哪个隔板上后,就可以按掉落的方向建图,显然图是一个 DAG,按拓扑序简单 dp 即可求出答案。
时间复杂度 \(O((n+w)\log(n+w)\log w)\)。
代码
#include <bits/stdc++.h>
using namespace std;
#define pii pair<int,int>
#define ll long long
const int N=1e5+5,P=1e9+7,inf=2e9;
int h,w,n,q,to[N*3],in[N*2],f[N*2];
vector<int> e[N*2];
struct ball
{
int u,l,r,s;
}a[N];
struct drop
{
int op,id,l,r,h,mx;
}b[N*4];
namespace sgt
{
int val[N*4],tag[N*4];
void init()
{
val[1]=tag[1]=0;
}
void pushdown(int x)
{
if(tag[x]!=-1)
{
tag[x*2]=tag[x*2+1]=val[x*2]=val[x*2+1]=tag[x];
tag[x]=-1;
}
}
void update(int pl,int pr,int v,int x=1,int dl=1,int dr=w)
{
if(dl>=pl&&dr<=pr)
{
val[x]=tag[x]=v;
return;
}
pushdown(x);
int mid=(dl+dr)>>1;
if(mid>=pl)
update(pl,pr,v,x*2,dl,mid);
if(mid<pr)
update(pl,pr,v,x*2+1,mid+1,dr);
}
int query(int p,int x=1,int dl=1,int dr=w)
{
if(dl==dr)
return val[x];
pushdown(x);
int mid=(dl+dr)>>1;
if(mid>=p)
return query(p,x*2,dl,mid);
return query(p,x*2+1,mid+1,dr);
}
}
void solve(int l,int r)
{
if(l==r)
return;
int mid=(l+r)>>1;
solve(l,mid);
solve(mid+1,r);
sort(b+l,b+mid+1,[](drop u,drop v){return u.h<v.h;});
sort(b+mid+1,b+r+1,[](drop u,drop v){return u.h<v.h;});
sgt::init();
int j=l;
for(int i=mid+1;i<=r;i++)
{
while(j<=mid&&b[j].h<b[i].h)
{
if(!b[j].op)
sgt::update(b[j].l,b[j].r,b[j].id);
j++;
}
if(b[i].op)
{
int p=sgt::query(b[i].l);
if(a[p].u>a[to[b[i].op]].u)
to[b[i].op]=p;
}
}
}
signed main()
{
scanf("%d%d%d",&h,&w,&n);
for(int i=1;i<=w*4;i++)
sgt::tag[i]=-1;
int tot=0;
for(int i=1;i<=w;i++)
b[++q]={++tot,n+i,i,0,h+1,h+1};
for(int i=1;i<=n;i++)
{
scanf("%d%d%d%d",&a[i].u,&a[i].l,&a[i].r,&a[i].s);
b[++q]={0,i,a[i].l,a[i].r,a[i].u,a[i].u+a[i].s};
b[++q]={++tot,i,a[i].l>1?a[i].l-1:a[i].r+1,0,a[i].u,a[i].u};
b[++q]={++tot,i,a[i].r<w?a[i].r+1:a[i].l-1,0,a[i].u,a[i].u};
}
sort(b+1,b+1+q,[](drop u,drop v){return u.mx==v.mx?u.op<v.op:u.mx>v.mx;});
solve(1,q);
tot=0;
for(int i=1;i<=w;i++)
{
e[n+i].push_back(to[++tot]);
in[to[tot]]++;
}
for(int i=1;i<=n;i++)
{
e[i].push_back(to[++tot]);
in[to[tot]]++;
e[i].push_back(to[++tot]);
in[to[tot]]++;
}
queue<int> que;
for(int i=1;i<=n+w;i++)
if(!in[i])
{
que.push(i);
if(i>n)
f[i]++;
}
while(que.size())
{
int x=que.front();
que.pop();
for(int y:e[x])
{
(f[y]+=f[x])%=P;
in[y]--;
if(!in[y])
que.push(y);
}
}
printf("%d",f[0]);
return 0;
}

浙公网安备 33010602011771号