zoukankan      html  css  js  c++  java
  • 【BZOJ3073】[PA2011] Journeys(线段树优化建图模板)

    点此看题面

    大致题意:(n)个点,每次在区间([a,b])和区间([c,d])之间连一条无向边,求从起点出发到所有点的最短路。

    线段树优化建图模板

    一道板子题。

    考虑建两棵线段树,一棵表示出边,一棵表示入边。

    初始化建树时,出边线段树上每个子节点向父节点连边,入边线段树上每个父节点向子节点连边。

    然后对于一次连边操作,我们把无向边拆成两条有向边,从一个区间向另一个区间连边。

    则我们可以新建一个虚拟节点,在出边线段树上区间向该节点连边,然后由该节点向入边线段树上的区间连边。

    注意这两条边中只需一条权值设为(1),不然答案会翻倍。

    最后还要记得从出边线段树上每个叶节点向入边线段树上自身的对应节点连边。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 500000
    #define M 100000
    #define DT 5000000
    #define ET 10000000
    #define add(x,y,v) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y,e[ee].val=v)
    using namespace std;
    int n,m,s,tot,ee,lnk[DT+5];struct edge {int to,nxt,val;}e[2*ET+5];
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=(x<<3)+(x<<1)+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    		Tp I void writeln(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);pc('
    ');} 
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    		#undef D
    }F;
    template<int op> class SegmentTree//线段树优化建图,op=0为出边线段树,op=1为入边线段树
    {
    	private:
    		#define PT CI l=1,CI r=n,CI rt=1
    		#define LT l,mid,rt<<1
    		#define RT mid+1,r,rt<<1|1
    		int P[N<<2];
    	public:
    		I void Build(PT)//建树
    		{
    			if(l==r) return (void)(P[rt]=(op^(l==s))?l:n+l);int mid=l+r>>1;P[rt]=++tot,
    			Build(LT),op?add(P[rt],P[rt<<1],0):add(P[rt<<1],P[rt],0),
    			Build(RT),op?add(P[rt],P[rt<<1|1],0):add(P[rt<<1|1],P[rt],0);
    		}
    		I void Add(CI L,CI R,CI t,PT)//连边
    		{
    			if(L<=l&&r<=R) return (void)(op?add(t,P[rt],op):add(P[rt],t,op));int mid=l+r>>1;
    			L<=mid&&(Add(L,R,t,LT),0),R>mid&&(Add(L,R,t,RT),0);
    		}
    };SegmentTree<0> SO;SegmentTree<1> SI;
    class Dijkstra//最短路
    {
    	private:
    		#define mp make_pair
    		#define fir first
    		#define sec second
    		int dis[DT+5],vis[DT+5];typedef pair<int,int> Pr;
    		priority_queue<Pr,vector<Pr>,greater<Pr> > q;
    	public:
    		I int operator [] (CI x) Con {return dis[x];}
    		I void Dij(CI s)
    		{
    			RI i;Pr k;for(i=1;i<=tot;++i) dis[i]=1e9;q.push(mp(dis[s]=0,s));//初始化
    			W(!q.empty())
    			{
    				if(k=q.top(),q.pop(),vis[k.sec]) continue;vis[k.sec]=1;
    				for(i=lnk[k.sec];i;i=e[i].nxt) k.fir+e[i].val<dis[e[i].to]&&
    					(q.push(mp(dis[e[i].to]=k.fir+e[i].val,e[i].to)),0);
    			}
    		}
    }D;
    int main()
    
    	RI i,a,b,c,d;F.read(n,m,s),tot=2*n,SO.Build(),SI.Build();//初始化
    	for(i=1;i<=n;++i) i^s&&add(i,n+i,0);//从出边线段树向入边线段树对应点连边
    	for(i=1;i<=m;++i) F.read(a,b,c,d),
    		++tot,SO.Add(a,b,tot),SI.Add(c,d,tot),//把无向边拆成两条有向边
    		++tot,SO.Add(c,d,tot),SI.Add(a,b,tot);
    	for(D.Dij(s),i=1;i<=n;++i) F.writeln(D[i]);return F.clear(),0;
    }
    
  • 相关阅读:
    JAVA共通関数入力パラメータをダブルクォートで囲む
    JAVA共通関数 システム時刻を取得する(2)
    JAVA共通関数ーー日付変換(YYYYMMDD → YYYY年MM月DD日)を行う
    JAVA共通関数文字変換 & " をHTML用に変換する(改行はタグで置き換え)
    JAVA共通関数日付変換(YYYYMMDD → YYYY/MM/DD)を行う
    JAVA共通関数--カンマ削除(数値からカンマを取り除く)を行う
    JAVASCRIPT共通関数デジタル時計を表示する
    JAVASCRIPT共通関数フォームの飛び先変更
    JAVA共通関数ーー数値フォーマット(数値をカンマ付きに編集)を行う
    VSCode linux下正确支持查找引用 "Find all reference"
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ3073.html
Copyright © 2011-2022 走看看