【分治】BZOJ4979 [Lydsy八月月赛] 凌晨三点的宿舍

编程入门 行业动态 更新时间:2024-10-12 20:22:35

【分治】BZOJ4979 [Lydsy八月月赛] 凌晨<a href=https://www.elefans.com/category/jswz/34/1741309.html style=三点的宿舍"/>

【分治】BZOJ4979 [Lydsy八月月赛] 凌晨三点的宿舍

【题目】
原题地址
给定一个 n n 栋的公寓,第i" role="presentation">i栋公寓高 hi h i ,对于一个房间,它上下左右四个方向的房间和它距离为1。现在有 m m 个亮灯的房间,问这些房间中距离不超过k" role="presentation">k的有多少对。

【题目分析】
第一眼看到这题,感觉这是一棵树。又看了看数据范围,不会是个树分治吧?
不过想了一会发现不是很可做,然后考虑单独抽出一段区间的公寓怎么做,然后就可以分治了。
(实际上就是一眼看破是分治了好不好,虽然我不太会做啦)

【解题思路】
这道题还是不错的qwq。
对于两个房间 A,B A , B ,不妨设 xA≤xB x A ≤ x B ,那么有:

dis(A,B)=xB−xA+yA+yB−2×min(yA,yB,hxA,hxA+1,…,hxB) d i s ( A , B ) = x B − x A + y A + y B − 2 × m i n ( y A , y B , h x A , h x A + 1 , … , h x B )
若 xA=xB x A = x B ,那么直接按照 y y 排序然后双指针统计答案即可,接下来只需要考虑xA&lt;xB" role="presentation">xA<xB的情况。
对序列 h h 进行分治,设solve(l,r)" role="presentation">solve(l,r)表示处理所有 l≤xA<xB≤r l ≤ x A < x B ≤ r 的点对。
取 mid=⌊l+r2⌋ m i d = ⌊ l + r 2 ⌋ ,那么递归调用 solve(l,mid) s o l v e ( l , m i d ) 和 solve(mid+1,r) s o l v e ( m i d + 1 , r ) 后,只需要处理 l≤xA≤mid<xB≤r l ≤ x A ≤ m i d < x B ≤ r 的点对。
设 fi f i 表示 min(hi,hi+1,…,hmid) m i n ( h i , h i + 1 , … , h m i d ) , gi g i 表示 min(hmid+1,…,hi−1,hi) m i n ( h m i d + 1 , … , h i − 1 , h i ) ,则:
dis(A,B)=xB−xA+yA+yB−2×min(yA,yB,hxA,hxA+1,…,hxB)=xB−xA+yA+yB−2×min(min(yA,fxA),min(yB,gxB)) d i s ( A , B ) = x B − x A + y A + y B − 2 × m i n ( y A , y B , h x A , h x A + 1 , … , h x B ) = x B − x A + y A + y B − 2 × m i n ( m i n ( y A , f x A ) , m i n ( y B , g x B ) )
枚举 min m i n 落在 A A 还是B" role="presentation">B,扫描线 + 树状数组统计即可。
时间复杂度 O(nlogn+mlog2n) O ( n l o g n + m l o g 2 n )

话说我迷之RE,怒开2倍过了。。。

【参考代码】

#include<bits/stdc++.h>
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.w<B.w;
}void work(int 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(j<qs && q[j+1]-q[i]<=k)++j;ans+=j-i;}
}int lowbit(int x)
{return x&(-x);
}void update(int x)
{x+=N;for(;x<M;x+=lowbit(x))if(vis[x]<T)vis[x]=T,tr[x]=1;elsetr[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].w<qa[j].w)update(qa[j].y-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。

更多推荐

【分治】BZOJ4979 [Lydsy八月月赛] 凌晨三点的宿舍

本文发布于:2024-02-24 16:08:28,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1695891.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:三点   宿舍   Lydsy   凌晨

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!