【题目】
原题地址
给定一个 n n 栋的公寓,第 i i 栋公寓高 hi h i ,对于一个房间,它上下左右四个方向的房间和它距离为1。现在有 m m 个亮灯的房间,问这些房间中距离不超过 k k 的有多少对。
【题目分析】
第一眼看到这题,感觉这是一棵树。又看了看数据范围,不会是个树分治吧?
不过想了一会发现不是很可做,然后考虑单独抽出一段区间的公寓怎么做,然后就可以分治了。
(实际上就是一眼看破是分治了好不好,虽然我不太会做啦)
【解题思路】
这道题还是不错的qwq。
对于两个房间 A,B A , B ,不妨设 xA≤xB x A ≤ x B ,那么有:
话说我迷之RE,怒开2倍过了。。。
【参考代码】
#include
using namespace std;
typedef long long LL;
const int N=2e5+10;
const int M=N*3;
int n,m,k,tot,T;
int h[N<<1],g[N<<1],q[N<<1],head[N<<1];
int tr[M<<1],vis[M<<1];
LL ans;
struct Tway
{
int v,nex;
Tway(){}
Tway(int vv,int nexx){
v=vv;nex=nexx;
}
};
Tway e[M<<1];
struct Tnode
{
int w,x,y;
Tnode(){}
Tnode(int ww,int xx,int yy){
w=ww;x=xx;y=yy;
}
};
Tnode qa[N],qb[N];
void add(int u,int v)
{
e[++tot]=(Tway){v,head[u]};head[u]=tot;
}
bool cmp(Tnode A,Tnode B)
{
return A.wint x)
{
int qs=0;
for(int i=head[x];i;i=e[i].nex)
q[++qs]=e[i].v;
if(qs<=1)
return;
sort(q+1,q+qs+1);
for(int i=1,j=1;i<=qs;++i)
{
while(jq[j+1]-q[i]<=k)
++j;
ans+=j-i;
}
}
int lowbit(int x)
{
return x&(-x);
}
void update(int x)
{
x+=N;
for(;xx+=lowbit(x))
if(vis[x]x]=T,tr[x]=1;
else
tr[x]++;
}
void query(int x)
{
x=min(x+N,M-1);
for(;x>0;x-=lowbit(x))
if(vis[x]==T)
ans+=tr[x];
}
void solve(int l,int r)
{
if(l==r)
return;
int mid=(l+r)>>1,ca=0,cb=0;
solve(l,mid);solve(mid+1,r);
for(int i=mid,tp=N;i>=l;--i)
{
tp=min(tp,h[i]);
for(int j=head[i];j;j=e[j].nex)
qa[++ca]=(Tnode){min(tp,e[j].v),i,e[j].v};
}
for(int i=mid+1,tp=N;i<=r;++i)
{
tp=min(tp,h[i]);
for(int j=head[i];j;j=e[j].nex)
qb[++cb]=(Tnode){min(tp,e[j].v),i,e[j].v};
}
if(!ca || !cb)
return;
sort(qa+1,qa+ca+1,cmp);
sort(qb+1,qb+cb+1,cmp);
++T;
for(int i=ca,j=cb;i;--i)
{
while(j && qa[i].w<=qb[j].w)
update(qb[j].x+qb[j].y),--j;
query(k+2*qa[i].w+qa[i].x-qa[i].y);
}
++T;
for(int i=cb,j=ca;i;--i)
{
while(j && qb[i].wy-qa[j].x),--j;
query(k+2*qb[i].w-qb[i].x-qb[i].y);
}
}
int main()
{
freopen("BZOJ4979.in","r",stdin);
freopen("BZOJ4979.out","w",stdout);
scanf("%d%d",&n,&k);
for(int i=1;i<=n;++i)
scanf("%d",&h[i]);
scanf("%d",&m);
for(int i=1;i<=m;++i)
{
int u,v;
scanf("%d%d",&u,&v);
add(u,v);
}
for(int i=1;i<=n;++i)
work(i);
solve(1,n);
printf("%lld\n",ans);
return 0;
}
【总结】
水了这么久题目终于遇到一道难一点的分治题了qwq。