• [NOI2019]弹跳(KD-Tree/四分树/线段树套平衡树 优化建图+Dijkstra)


    本题可以用的方法很多,除去以下三种我所知道的就还有至少三种。

    方法一:类似线段树优化建图,将一个平面等分成四份(若只有一行或一列则等分成两份),然后跑Dijkstra即可。建树是$O(nlog n)$的,单次连边是$O(nlog^2 n)$的。

     1 #include<queue>
     2 #include<vector>
     3 #include<cstdio>
     4 #include<cstring>
     5 #include<algorithm>
     6 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     7 #define For(i,x) for (int i=h[x],k; i; i=nxt[i])
     8 using namespace std;
     9 
    10 const int N=1000010,M=1500010;
    11 struct E{ int w,l,r,u,d; }p[N];
    12 struct P{ int u,d; };
    13 vector<int>G[N];
    14 int n,m,W,H,now,dis,x,y,cnt,rt,tot,h[N],to[M],nxt[M],w[M],vis[N],d[N],ch[N][4];
    15 bool operator <(P x,P y){ return x.d>y.d; }
    16 priority_queue<P>Q;
    17 void add(int x,int y,int z){ to[++cnt]=y; nxt[cnt]=h[x]; w[cnt]=z; h[x]=cnt; }
    18 
    19 void ins(int fa,int &k,int xl,int xr,int yl,int yr,int x,int y){
    20     if (x<xl||x>xr||y<yl||y>yr) return;
    21     if (!k) k=++tot;
    22     if (k!=rt) add(fa+n,k+n,0);
    23     if (xl==xr&&yl==yr){ add(k+n,now,0); return; }
    24     int xm=(xl+xr)>>1,ym=(yl+yr)>>1;
    25     ins(k,ch[k][0],xl,xm,yl,ym,x,y);
    26     ins(k,ch[k][1],xl,xm,ym+1,yr,x,y);
    27     ins(k,ch[k][2],xm+1,xr,yl,ym,x,y);
    28     ins(k,ch[k][3],xm+1,xr,ym+1,yr,x,y);
    29 }
    30 
    31 void link(int k,int xl,int xr,int yl,int yr,int xL,int xR,int yL,int yR){
    32     if (!k||xR<xl||xL>xr||yR<yl||yL>yr||d[k+n]<=dis) return;
    33     if (xl>=xL&&xr<=xR&&yl>=yL&&yr<=yR){ d[k+n]=dis; Q.push((P){k+n,d[k+n]}); return; }
    34     int xm=(xl+xr)>>1,ym=(yl+yr)>>1;
    35     link(ch[k][0],xl,xm,yl,ym,xL,xR,yL,yR);
    36     link(ch[k][1],xl,xm,ym+1,yr,xL,xR,yL,yR);
    37     link(ch[k][2],xm+1,xr,yl,ym,xL,xR,yL,yR);
    38     link(ch[k][3],xm+1,xr,ym+1,yr,xL,xR,yL,yR);
    39 }
    40 
    41 int main(){
    42     freopen("jump.in","r",stdin);
    43     freopen("jump.out","w",stdout);
    44     scanf("%d%d%d%d",&n,&m,&W,&H);
    45     rep(i,1,n) scanf("%d%d",&x,&y),now=i,ins(0,rt,1,W,1,H,x,y);
    46     rep(i,1,m) scanf("%d%d%d%d%d%d",&now,&p[i].w,&p[i].l,&p[i].r,&p[i].u,&p[i].d),G[now].push_back(i);
    47     memset(d,63,sizeof(d)); d[1]=0; Q.push((P){1,0});
    48     while (!Q.empty()){
    49         int u=Q.top().u; Q.pop();
    50         if (vis[u]) continue; vis[u]=1;
    51         for (int i=0;i<(int)G[u].size();i++)
    52             x=G[u][i],dis=d[u]+p[x].w,link(rt,1,W,1,H,p[x].l,p[x].r,p[x].u,p[x].d);
    53         For(i,u) if (d[k=to[i]]>d[u]+w[i]) Q.push((P){k,d[k]=d[u]+w[i]});
    54     }
    55     rep(i,2,n) printf("%d
    ",d[i]);
    56     return 0;
    57 }
    四分树

    方法二:一维使用线段树,另一维用set维护这行中的每个点。注意到在Dijikstra时,一条边至多被松弛一次,即一个矩阵至多被访问一次,所以访问并更新一个点之后就可以直接将其删去,复杂度$O(nlog^2 n+mlog m)$。

     1 #include<set>
     2 #include<queue>
     3 #include<vector>
     4 #include<cstdio>
     5 #include<algorithm>
     6 #define ls (x<<1)
     7 #define rs (ls|1)
     8 #define lson ls,l,mid
     9 #define rson rs,mid+1,r
    10 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
    11 using namespace std;
    12 typedef pair<int, int>pii;
    13 typedef multiset<pii>::iterator iter;
    14 
    15 const int N=70010,M=150010,S=(1<<18)+10;
    16 int n,m,W,H,x,p,id,yp[N],vis[N],dis[N],h[N],nxt[M],val[M],L[M],R[M],D[M],U[M];
    17 multiset<pii>st[S];
    18 priority_queue<pii> Q;
    19 
    20 void ins(int x,int l,int r,int k,int id){
    21     st[x].insert(pii(yp[id],id));
    22     if (l==r) return;
    23     int mid=(l+r)>>1;
    24     if (k<=mid) ins(lson,k,id); else ins(rson,k,id);
    25 }
    26 
    27 void del(int x,int l,int r,int id,int d){
    28     if (r<L[id] || R[id]<l) return;
    29     if (L[id]<=l && r<=R[id]){
    30         iter it=st[x].lower_bound(pii(D[id],0)),tmp;
    31         while (it!=st[x].end() && it->first<=U[id]){
    32             int u=it->second;
    33             if (!vis[u]){
    34                 vis[u]=1; dis[u]=d;
    35                 for (int j=h[u]; j; j=nxt[j]) Q.push(pii(-d-val[j],j));
    36             }
    37             tmp=it; it++; st[x].erase(tmp);
    38         }
    39         return;
    40     }
    41     int mid=(l+r)>>1; del(lson,id,d); del(rson,id,d);
    42 }
    43 
    44 int main(){
    45     freopen("jump.in","r",stdin);
    46     freopen("jump.out","w",stdout);
    47     scanf("%d%d%d%d",&n,&m,&W,&H);
    48     rep(i,1,n) scanf("%d%d",&x,&yp[i]),ins(1,1,W,x,i);
    49     rep(i,1,m) scanf("%d%d%d%d%d%d",&p,&val[i],&L[i],&R[i],&D[i],&U[i]),nxt[i]=h[p],h[p]=i;
    50     dis[1]=0; vis[1]=1;
    51     for (int i=h[1]; i; i=nxt[i]) Q.push(pii(-val[i],i));
    52     while (!Q.empty()){
    53         pii ed=Q.top(); Q.pop();
    54         int dis=-ed.first; id=ed.second; del(1,1,W,id,dis);
    55     }
    56     rep(i,2,n) printf("%d
    ",dis[i]);
    57     return 0;
    58 }
    线段树套set

    方法三:类似方法二地,用KD-Tree优化建图,树上每个点新建一个新点,每个叶子连向这个坐标对应的点。同样在Dijkstra时,每次访问并更新时删除这个点。复杂度可能可以用一些做到$O(nlog^2 n)$,但这里没用。

     1 #include<set>
     2 #include<queue>
     3 #include<cstdio>
     4 #include<vector>
     5 #include<cstring>
     6 #include<algorithm>
     7 #define rep(i,l,r) for (int i=(l); i<=(r); i++)
     8 using namespace std;
     9 
    10 const int N=70010,inf=0x3f3f3f3f;
    11 int n,m,w,h,rt,D,cnt,id[N*2],dis[N*2],vis[N*2];
    12 int nu,nt,xl,xr,yl,yr,nd[N*2],len;
    13 
    14 struct data{
    15     int nt,xl,xr,yl,yr;
    16     bool operator>(const data &b)const{ return nt>b.nt; }
    17 };
    18 
    19 vector<data>f[N*2];
    20 priority_queue<data,vector<data>,greater<data> >Q;
    21 
    22 struct P{
    23     int x[2],id;
    24     bool operator<(const P&b)const{ return x[D]!=b.x[D] ? x[D]<b.x[D] : x[D^1]<b.x[D^1]; }
    25 }p[N];
    26 
    27 struct Tr{ int mx[2],mn[2],lc,rc,siz; }t[N*2];
    28 
    29 void upd(int u){
    30     t[u].mn[0]=t[u].mn[1]=inf;
    31     t[u].mx[0]=t[u].mx[1]=-inf;
    32     t[u].siz=1; int v=t[u].lc;
    33     if (v){
    34         t[u].siz+=t[v].siz;
    35         t[u].mx[0]=max(t[u].mx[0],t[v].mx[0]),t[u].mx[1]=max(t[u].mx[1],t[v].mx[1]);
    36         t[u].mn[0]=min(t[u].mn[0],t[v].mn[0]),t[u].mn[1]=min(t[u].mn[1],t[v].mn[1]);
    37     }
    38     v=t[u].rc;
    39     if (v){
    40         t[u].siz+=t[v].siz;
    41         t[u].mx[0]=max(t[u].mx[0],t[v].mx[0]),t[u].mx[1]=max(t[u].mx[1],t[v].mx[1]);
    42         t[u].mn[0]=min(t[u].mn[0],t[v].mn[0]),t[u].mn[1]=min(t[u].mn[1],t[v].mn[1]);
    43     }
    44 }
    45 
    46 int bud(int l,int r,int wd){
    47     int u=++cnt,mid=(l+r)>>1;t[u].siz=1;
    48     if (l==r){
    49         id[u]=p[l].id;
    50         t[u].mn[0]=t[u].mx[0]=p[l].x[0];
    51         t[u].mn[1]=t[u].mx[1]=p[l].x[1];
    52         return u;
    53     }
    54     bool flag=1;
    55     rep(i,l+1,r) if(p[i].x[wd]!=p[i-1].x[wd])flag=0;
    56     if (flag) wd^=1;
    57     D=wd; nth_element(p+l,p+mid,p+1+r);
    58     t[u].lc=bud(l,mid,wd^1); t[u].rc=bud(mid+1,r,wd^1);
    59     upd(u); return u;
    60 }
    61 
    62 void dfs(int u){
    63     if (!t[u].siz)return;
    64     if (t[u].mn[0]>xr||t[u].mx[0]<xl||t[u].mn[1]>yr||t[u].mx[1]<yl)return;
    65     if (id[u]){ nd[++len]=id[u]; t[u].siz=0; return; }
    66     dfs(t[u].lc); dfs(t[u].rc);
    67     t[u].siz=t[t[u].lc].siz+t[t[u].rc].siz;
    68 }
    69 
    70 int main(){
    71     freopen("jump.in","r",stdin);
    72     freopen("jump.out","w",stdout);
    73     memset(dis,63,sizeof(dis));
    74     scanf("%d%d%d%d",&n,&m,&w,&h);
    75     rep(i,1,n) scanf("%d%d",&p[i].x[0],&p[i].x[1]),p[i].id=i;
    76     rt=bud(1,n,0);
    77     rep(i,1,m){
    78         scanf("%d%d%d%d%d%d",&nu,&nt,&xl,&xr,&yl,&yr);
    79         f[nu].push_back((data){nt,xl,xr,yl,yr});
    80     }
    81     dis[1]=0; vis[1]=1;
    82     for(int i=0; i<(int)f[1].size(); i++) Q.push(f[1][i]);
    83     while (!Q.empty()){
    84         nt=Q.top().nt,xl=Q.top().xl,xr=Q.top().xr,yl=Q.top().yl,yr=Q.top().yr;
    85         Q.pop(); len=0; dfs(rt);
    86         rep(i,1,len){
    87             int u=nd[i];
    88             if (vis[u])continue; vis[u]=1;
    89             dis[u]=nt;
    90             for (int j=0; j<(int)f[u].size(); ++j){
    91                 data tp=f[u][j]; tp.nt+=nt; Q.push(tp);
    92             }
    93         }
    94     }
    95     rep(i,2,n) printf("%d
    ",dis[i]);
    96     return 0;
    97 }
    KD-Tree
  • 相关阅读:
    Dede CMS如何在文章中增加“附件下载”操作说明
    仿站模仿的三个网站
    PHP面相对象中的重载与重写
    面向对象思想
    最常用的正则表达式
    PHP第二阶段学习 一、php的基本语法
    PHP isset()与empty()的使用区别详解
    mysql索引总结----mysql 索引类型以及创建
    MySQL实现当前数据表的所有时间都增加或减少指定的时间间隔
    T-SQL语句以及几个数据库引擎
  • 原文地址:https://www.cnblogs.com/HocRiser/p/11272591.html
Copyright © 2020-2023  润新知