题解 P5471 【[NOI2019]弹跳】

做法:思维+动态开点线段树+分块

首先我们考虑最短路做法,发现边数是级别的。一维的情况我们能用线段树优化建边,但二维呢?反正我不会。

我们想到Dijkstra的思想,每次找到dis最小的点,并用这个点去更新其他点。

我们把矩形看成点,相当于每次找出dis最小的矩形,然后更新矩形中的点。

但一次性更新矩形中的全部点肯定不现实,我们就可以每次更新矩形中的一个点即可。

现在的问题就是如何找矩形中的一个点。发现有点难办啊。

一开始我想到是用树套树找点,结果被卡空间(QAQ),两只log的空间刚好被卡,舒适。

然后我们就考虑如何优化空间。大家都知道时间换空间吧,我就是这么想的。

我们可以分块套动态开点线段树。我们对每x轴上的每一个点建一颗动态开点线段树,空间为。再维护个动态开点线段树记录每一块的情况,空间为

总算是把空间卡进去了。

每次查询我们先找到目标的块,然后在块上的动态开点线段树上二分找到一个点即可。

由于只要找一个点,找到了就可以return。所以时间复杂度不到极限的,卡卡常就能过。

代码:

#include<bits/stdc++.h>
using namespace std;
#define next Next
#define mid (l+r)/2
const int N=70285;
int n,m,size,num,cnt,top,gs,ID,w,h,x[N],y[N],LL[N],RR[N],bel[N],Ans[N],tree[N],L[(N<<6)+1000000],R[(N<<6)+1000000],sum[(N<<6)+1000000];
multiset<int>xu[2*N];
int mp[(N<<6)+1000000];
char buf[1<<21],*p1=buf,*p2=buf;
inline int gc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
inline int read()
{
    int ret=0,f=0;char c=gc();
    while(!isdigit(c)){if(c=='-')f=1;c=gc();}
    while(isdigit(c)){ret=ret*10+c-48;c=gc();}
    if(f)return -ret;return ret;
}
struct node{
    int val,l,r,d,u;
};
vector<node>g[N];
bool operator < (node a,node b)
{
    return a.val>b.val;
}
priority_queue<node>q;
void update(int &rt,int l,int r,int x,int id,int val)
{
    if(!rt)rt=++cnt;
    sum[rt]+=val;
    if(l==r)
    {
        int xjh=0;
        if(mp[rt])xjh=mp[rt];
        else{
            xjh=++top;
            mp[rt]=top;
        }
        if(val==1)xu[xjh].insert(id);
        else xu[xjh].erase(id);
        return;
    }
    if(x<=mid)update(L[rt],l,mid,x,id,val);
    else update(R[rt],mid+1,r,x,id,val);
}
void change(int x,int y,int id,int val)
{
    update(tree[x],1,h,y,id,val);
    update(tree[n+bel[x]],1,h,y,id,val);
}
void Zhao(int rt,int l,int r)
{
    if(l==r)
    {
        int xjh=mp[rt];
        ID=*xu[xjh].begin();
        return;
    }
    if(sum[L[rt]])Zhao(L[rt],l,mid);
    else Zhao(R[rt],mid+1,r);
}
void query(int &rt,int l,int r,int x,int y)
{
    if(!rt)return;
    if(sum[rt]==0)return;
    if(ID!=-1)return;
    if(l==x&&r==y)
    {
        Zhao(rt,l,r);
        return;
    }
    if(y<=mid)query(L[rt],l,mid,x,y);
    else if(x>mid)query(R[rt],mid+1,r,x,y);
    else{
        query(L[rt],l,mid,x,mid);
        query(R[rt],mid+1,r,mid+1,y);
    }
}
void find(int l,int r,int d,int u)
{
    if(bel[l]==bel[r]||bel[l]+1==bel[r])
    {
        for(int i=l;i<=r;i++)
        {
            query(tree[i],1,h,d,u);
            if(ID!=-1)return;
        }
        return;
    }
    for(int i=bel[l]+1;i<=bel[r]-1;i++)
    {
        query(tree[n+i],1,h,d,u);
        if(ID!=-1)return;
    }
    if(LL[bel[l]]==l)
    {
         query(tree[n+bel[l]],1,h,d,u);
        if(ID!=-1)return;       
    }
    else{
        for(int i=l;i<=RR[bel[l]];i++)
        {
            query(tree[i],1,h,d,u);
            if(ID!=-1)return;
        }
    }
    if(RR[bel[r]]==r)
    {
         query(tree[n+bel[r]],1,h,d,u);
        if(ID!=-1)return;       
    }
    else{
        for(int i=LL[bel[r]];i<=r;i++)
        {
            query(tree[i],1,h,d,u);
            if(ID!=-1)return;
        }
    }
}
void write(int x)
{
    if(x<10)
    {
        putchar('0'+x);
        return;
    }
    write(x/10);
    putchar('0'+x%10);
}
signed main()
{
    freopen("jump.in","r",stdin);
    freopen("jump.out","w",stdout);
    n=read();m=read();w=read();h=read();w=h=0;
    for(int i=1;i<=n;i++)x[i]=read(),y[i]=read();
    for(int i=1;i<=m;i++)
    {
        int x=read(),y=read(),l=read(),r=read(),d=read(),u=read();
        w=max(w,r);
        h=max(h,u);
        g[x].push_back((node){y,l,r,d,u});
    }
    size=sqrt(w);
    num=w/size;
    if(w%size)num++;
    for(int i=1;i<=num;i++)LL[i]=w+1;
    for(int i=1;i<=w;i++)
    {
        bel[i]=(i-1)/size+1;
        LL[bel[i]]=min(LL[bel[i]],i);
        RR[bel[i]]=max(RR[bel[i]],i);
    }
    for(int i=2;i<=n;i++)change(x[i],y[i],i,1);
    gs=1;
    for(int i=0;i<g[1].size();i++)
    {
        node u=g[1][i];
        q.push((node){u.val,u.l,u.r,u.d,u.u});
    }
    while(gs<n)
    {
        if(q.empty())break;
        node u=q.top();
        ID=-1;
        find(u.l,u.r,u.d,u.u);
        if(ID==-1)
        {
            q.pop();
            continue;
        }
        Ans[ID]=u.val;
        change(x[ID],y[ID],ID,-1);
        for(int i=0;i<g[ID].size();i++)
        {
            node x=g[ID][i];
            q.push((node){u.val+x.val,x.l,x.r,x.d,x.u});
        }
        gs++;
    }
    for(int i=2;i<=n;i++)write(Ans[i]),putchar('\n');
    return 0;
}