bzoj 3073 Journeys —— 线段树优化连边

题目:https://www.lydsy.com/JudgeOnline/problem.php?id=3073

建两棵线段树,一棵从下往上连边,一棵从上往下连边,叶子节点之间也有连边;

区间向区间连边时,可以新建一个节点,log2n 条边就能变成 2logn 条边;

注意区间向区间连边也要连反边,别忘了连反边时 ++cnt !

代码如下:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<queue>
#define mid ((l+r)>>1)
using namespace std;
int const xxn=5e5+5,xn=4e6+5,xm=3e7+5;
int n,m,hd[xn],ct,to[xm],nxt[xm],w[xm],dis[xn];
int rt[2],cnt,ls[xxn<<2],rs[xxn<<2],st[xxn],ed[xxn];
bool vis[xn];
struct N{
  int d,id;
  bool operator < (const N &y) const
  {return d==y.d?id<y.id:d>y.d;}
};
priority_queue<N>q;
int rd()
{
  int ret=0,f=1; char ch=getchar();
  while(ch<'0'||ch>'9'){if(ch=='-')f=0; ch=getchar();}
  while(ch>='0'&&ch<='9')ret=(ret<<3)+(ret<<1)+ch-'0',ch=getchar();
  return f?ret:-ret;
}
int gt[20];
void wr(int x)
{
  if(!x){puts("0"); return;}
  if(x<0)putchar('-'),x=-x;
  int t=0;
  while(x)gt[++t]=x%10,x/=10;
  for(int i=t;i;i--)putchar(gt[i]+'0');
  puts("");
}
void add(int x,int y,int z){to[++ct]=y; nxt[ct]=hd[x]; w[ct]=z; hd[x]=ct;}
void build(int x,int l,int r,bool tp)
{
  if(l==r)
    {
      if(!tp)st[l]=x; else ed[l]=x;
      return;
    }
  ls[x]=++cnt; rs[x]=++cnt;
  build(ls[x],l,mid,tp); build(rs[x],mid+1,r,tp);
  if(!tp)add(ls[x],x,0),add(rs[x],x,0);
  else add(x,ls[x],0),add(x,rs[x],0);
}
void link(int x,int l,int r,int L,int R,int c,bool tp)
{
  if(l>=L&&r<=R)
    {
      if(!tp)add(x,c,1); else add(c,x,0);
      return;
    }
  if(mid>=L)link(ls[x],l,mid,L,R,c,tp);
  if(mid<R)link(rs[x],mid+1,r,L,R,c,tp);
}
void dij(int s)
{
  memset(dis,0x3f,sizeof dis);
  dis[s]=0; q.push((N){0,s});
  while(q.size())
    {
      int x=q.top().id; q.pop();
      if(vis[x])continue; vis[x]=1;
      for(int i=hd[x],u;i;i=nxt[i])
    if(dis[u=to[i]]>dis[x]+w[i])
      dis[u]=dis[x]+w[i],q.push((N){dis[u],u});
    }
}
int main()
{
  n=rd(); m=rd(); int p=rd();
  rt[0]=++cnt; build(rt[0],1,n,0);
  rt[1]=++cnt; build(rt[1],1,n,1);
  for(int i=1;i<=n;i++)add(ed[i],st[i],0);
  for(int i=1,a,b,c,d;i<=m;i++)
    {
      a=rd(); b=rd(); c=rd(); d=rd(); int t=++cnt;
      link(rt[0],1,n,a,b,t,0); link(rt[1],1,n,c,d,t,1);
      t=++cnt;//!!!
      link(rt[0],1,n,c,d,t,0); link(rt[1],1,n,a,b,t,1);
    }
  dij(ed[p]);
  for(int i=1;i<=n;i++)wr(dis[ed[i]]);
  return 0;
}

 

posted @ 2018-10-29 11:29  Zinn  阅读(187)  评论(0编辑  收藏  举报