zoukankan      html  css  js  c++  java
  • [NOI2019] 弹跳

    题意:

    给你平面上的$n$个点,共有$m$个弹跳装置。

    每个弹跳装置可以从点$p_{i}$以$t_{i}$的代价跳到矩形$(L_{i},D_{i}),(R_{i},U_{i})$中的任何一个点。

    现在请你对于每座城市求出从1号点跳到它的最小代价。

    $nleq 70000,mleq 150000$。

    题解:不把边建出来的$KD-tree$优化建图。

    看一眼就知道$KD-tree$优化建图,但如果把所有边都建出来就爆炸了。

    设原图上的点是实点,$KD-tree$上的点(代表一个实点和一个矩形)是虚点。

    那么在$Dijkstra$到每个点的时候:

    • 若是实点,在$KD-tree$上查找能连的虚点/实点并向其连带权边。
    • 若是虚点,向它的两个儿子和它对应的实点连权为0的边。

    时间复杂度$O(msqrt{n})$,空间复杂度$O(msqrt{n})$(实际上只有优先队列可能达到这个空间,其他都是$O(n)$)。

    没了。不知道为什么有人写线段树。

    代码:

    #include<bits/stdc++.h>
    #define maxn 200005
    #define maxm 500005
    #define inf 0x7fffffff
    #define ll long long
    #define rint register int
    #define debug(x) cerr<<#x<<": "<<x<<endl
    #define fgx cerr<<"--------------"<<endl
    #define dgx cerr<<"=============="<<endl
    
    using namespace std;
    struct Point{int x[2],iid;}p[maxn];
    int mx[maxn][2],mn[maxn][2],id[maxn],ls[maxn],rs[maxn];
    int tot,np,dis[maxn<<1],vis[maxn<<1],tim[maxn];
    int L[maxn],R[maxn],D[maxn],U[maxn];
    struct node{int u,d;bool operator<(const node &b)const{return d>b.d;}};
    priority_queue<node> q; vector<int> vc[maxn];
    
    inline int read(){
        int x=0,f=1; char c=getchar();
        for(;!isdigit(c);c=getchar()) if(c=='-') f=-1;
        for(;isdigit(c);c=getchar()) x=x*10+c-'0';
        return x*f;
    }
    
    inline node md(int u,int d){node res;res.u=u,res.d=d;return res;}
    inline void upd(int u,int v){if(dis[u]>v){dis[u]=v,q.push(md(u,v));}}
    inline bool ok(int xa,int ya,int xb,int yb){return xb<=xa&&ya<=yb;}
    inline bool cmp(Point a,Point b){return (!np)?(a.x[0]<b.x[0]):(a.x[1]<b.x[1]);}
    inline void pushup(int k){
        for(rint i=0;i<2;i++){
            mx[k][i]=mn[k][i]=p[id[k]].x[i];
            if(ls[k]) mx[k][i]=max(mx[k][i],mx[ls[k]][i]),mn[k][i]=min(mn[k][i],mn[ls[k]][i]);
            if(rs[k]) mx[k][i]=max(mx[k][i],mx[rs[k]][i]),mn[k][i]=min(mn[k][i],mn[rs[k]][i]);
        }
    }
    inline int build(int l,int r,int type){
        if(l>r) return 0;
        int mid=l+r>>1,k=++tot; 
        id[k]=mid,np=type;
        nth_element(p+l,p+mid,p+r+1,cmp);
        ls[k]=build(l,mid-1,type^1);
        rs[k]=build(mid+1,r,type^1);
        pushup(k); return k;
    }
    inline void add(int l,int r,int d,int u,int c,int k){
        if(mx[k][0]<l || mn[k][0]>r || mx[k][1]<d || mn[k][1]>u) return;
        if(ok(mn[k][0],mx[k][0],l,r)&&ok(mn[k][1],mx[k][1],d,u)){upd(k,c);return;}   
        if(ok(p[id[k]].x[0],p[id[k]].x[0],l,r)&&ok(p[id[k]].x[1],p[id[k]].x[1],d,u)) upd(p[id[k]].iid,c);
        if(ls[k]) add(l,r,d,u,c,ls[k]); if(rs[k]) add(l,r,d,u,c,rs[k]);
    } 
    
    inline void Dijkstra(int s,int n){
        memset(vis,0,sizeof(vis));
        memset(dis,127,sizeof(dis));
        dis[s]=0,q.push(md(s,0));
        while(!q.empty()){
            rint u=q.top().u; q.pop();
            if(vis[u]) continue; vis[u]=1;
            if(u<=n) for(rint i=0;i<vc[u].size();i++) 
                add(L[vc[u][i]],R[vc[u][i]],D[vc[u][i]],U[vc[u][i]],dis[u]+tim[vc[u][i]],n+1);
            else upd(p[id[u]].iid,dis[u]),upd(ls[u],dis[u]),upd(rs[u],dis[u]);
        }
    }
    
    int main(){
        freopen("jump.in","r",stdin);
        freopen("jump.out","w",stdout);
        int n=read(),m=read(),w=read(),h=read();
        for(rint i=1;i<=n;i++) 
            p[i].x[0]=read(),p[i].x[1]=read(),p[i].iid=i;
        tot=n,build(1,n,0);
        for(rint i=1;i<=m;i++){
            int p=read();tim[i]=read();
            L[i]=read(),R[i]=read();
            D[i]=read(),U[i]=read();
            vc[p].push_back(i);
        }
        Dijkstra(1,n);
        for(rint i=2;i<=n;i++) printf("%d
    ",dis[i]);
        return 0;
    }
    D2T1
  • 相关阅读:
    kali 无线网络渗透测试
    kali 漏洞扫描
    Python复杂多重排序
    《编写高质量代码:改善Python程序的91个建议》读后感
    Python用format格式化字符串
    CDH安装Hadoop
    Python设计模式——状体模式
    HBase的安装与使用
    Python设计模式——观察者模式
    Python设计模式——建造者模式
  • 原文地址:https://www.cnblogs.com/YSFAC/p/12015060.html
Copyright © 2011-2022 走看看