Description
小Q所在的学校QNU(Quailty Niubi University)的学生公寓由n栋楼组成,这些楼从左往右连成一排,编号依次为1
到n,其中第i栋楼有h_i层。现在已经凌晨三点了,但是小Q和他的队友们仍然在刻苦地刷题,从他们房间窗户透出
的亮光格外醒目。
这时,辛苦了一晚上的小Q饿了,正当他拆完泡面准备倒水的时候,他发现热水壶放在队友那忘记拿回来了。无奈
之下,他只好走路去向队友要回热水壶。在学生公寓里,小Q每分钟可以选择上楼或者下楼,或者往左往右移动到
相邻的房间外面的过道上。因为夜晚的门禁,他不能走出公寓,同时,他也不能登上天台思考人生。你可以认为从
房间到过道不需要任何时间。饥饿的小Q最多只能坚持走k分钟,再之后他就会因为饥饿而昏倒。他历尽艰险终于从
队友那拿回了热水壶,解决了燃眉之急。这时,吃着泡面的小Q开始思考一个问题:如果他和队友的房间距离并没
有那么近,那么他就不会这么走运了。于是现在他想知道有多少对队友的房间之间的最短路程不超过k分钟。小Q正
在吃泡面,于是他把这个问题交给了你。请写一个程序帮助小Q解决这个现实问题。
题解
好题啊好题(向Claris低头QAQ)
此题做的时候只是扫了一眼,以为是双指针O(n)xjb维护一下,后来考完认真想了想发现萎的,无论怎么样都不能维护区间答案。。
%Claris
分治的想法比较显然了。
先把每一列上的处理一下,如果是同一列的双指针扫一遍就可以了。
分治处理不在同一列的点对。递归处理只在左半边和右半边,问题是如何处理跨越左右的。
dis(A,B)=xB−xA+yA+yB−2min(yA,yB,hxA,hxA+1,...,hxB)
dis(A,B)=xB−xA+yA+yB−2min(min(yA,fxA),min(yB,gxB))
那么,我们先预处理出f,g,然后用扫描线,双指针把左右区间按照min值从大到小处理一下,每次对于一个区间,用树状数组记录答案,然后直接加入,所以注意加一个时间戳,不同区间不能混了。
#include<cstdio>
#include<algorithm>
#include<cstring>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define fd(i,a,b) for(int i=a;i>=b;i--)
using namespace std;
const int N=2e5+10;
const int M=N*3;
int n,m,lim;
typedef long long ll;
ll ans;
int a[N],next[N],t[M],vis[M];
int tot,head[N],go[N],T;
struct node
{
int w,x,y;
node(){}
node(int w1,int x1,int y1)
{
w=w1;
x=x1;
y=y1;
}
}qa[N],qb[N];
inline int lowbit(int x)
{
return x&(-x);
}
inline bool cmp(const node&a,const node&b)
{
return a.w<b.w;
}
inline void add(int x,int y)
{
go[++tot]=y;
next[tot]=head[x];
head[x]=tot;
}
inline void work(int x)
{
int num=0;
static int b[N];
for(int i=head[x];i;i=next[i])
b[++num]=go[i];
if (num<=1)return;
sort(b+1,b+1+num);
int j=1;
fo(i,1,num)
{
while (j<num&&b[j+1]-b[i]<=lim)j++;
ans+=j-i;
}
}
inline void ins(int x)
{
x+=N;
while(x<M)
{
if (vis[x]<T)vis[x]=T,t[x]=1;
else t[x]++;
x+=lowbit(x);
}
}
inline void ask(int x)
{
x=min(x+N,M-1);
while (x>0)
{
if (vis[x]==T)ans+=t[x];
x-=lowbit(x);
}
}
inline void solve(int l,int r)
{
if (l==r)return;
int mid=(l+r)>>1,toa=0,tob=0;
solve(l,mid),solve(mid+1,r);
int k=N;
fd(i,mid,l)
{
if (k>a[i])k=a[i];
for(int j=head[i];j;j=next[j])
qa[++toa]=node(min(k,go[j]),i,go[j]);
}
k=N;
fo(i,mid+1,r)
{
if (k>a[i])k=a[i];
for(int j=head[i];j;j=next[j])
qb[++tob]=node(min(k,go[j]),i,go[j]);
}
if (!toa||!tob)return;
sort(qa+1,qa+1+toa,cmp);
sort(qb+1,qb+1+tob,cmp);
int i,j;
for(T++,i=toa,j=tob;i;i--)
{
while (j&&qa[i].w<=qb[j].w)ins(qb[j].y+qb[j].x),j--;
ask(lim+2*qa[i].w+qa[i].x-qa[i].y);
}
for(T++,i=tob,j=toa;i;i--)
{
while (j&&qb[i].w<qa[j].w)ins(qa[j].y-qa[j].x),j--;
ask(lim+2*qb[i].w-qb[i].x-qb[i].y);
}
}
int main()
{
scanf("%d%d",&n,&lim);
fo(i,1,n)scanf("%d",&a[i]);
scanf("%d",&m);
fo(i,1,m)
{
int x,y;
scanf("%d%d",&x,&y);
add(x,y);
}
fo(i,1,n)work(i);
solve(1,n);
printf("%lld\n",ans);
}