zoukankan      html  css  js  c++  java
  • [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
  • 相关阅读:
    Truck History(poj 1789)
    Highways poj 2485
    117. Populating Next Right Pointers in Each Node II
    116. Populating Next Right Pointers in Each Node
    115. Distinct Subsequences
    114. Flatten Binary Tree to Linked List
    113. Path Sum II
    109. Convert Sorted List to Binary Search Tree
    106. Construct Binary Tree from Inorder and Postorder Traversal
    105. Construct Binary Tree from Preorder and Inorder Traversal
  • 原文地址:https://www.cnblogs.com/HocRiser/p/11272591.html
Copyright © 2011-2022 走看看