zoukankan      html  css  js  c++  java
  • #线段树优化建图,Dijkstra#CF786B Legacy

    题目

    (n)个点的有向图,除了普通有向边((x,y,w))
    还有点(x)向区间([l,r])或区间([l',r'])向点(x')连边,
    问从点1到所有点的距离


    分析

    考虑最短路径,但是直接建边边数在(O(nm))级别内,
    考虑建两棵线段树,一棵下行边权为0,一棵上行边权为0,
    对于((x,y,w))直接连边即可,
    对于点(x)连向([l,r]),将区间拆成(O(logn))个线段树节点,
    并将点(x)连向下行的([l,r])线段树中,
    同理,上行的([l',r'])连向点(x')中,这样边数为(O(mlogn))
    加上Dijkstra的时间复杂度为(O(mlog^2n))


    代码

    #include <cstdio>
    #include <cctype>
    #include <algorithm> 
    #define rr register
    using namespace std;
    const int N=300011; typedef long long lll;
    struct node{int y,w,next;}e[N<<3]; pair<lll,int>heap[N];
    int Cnt,n,m,S,as[N],et=1,cnt,ls[N],rs[N],root; lll dis[N];
    inline signed iut(){
    	rr int ans=0; rr char c=getchar();
    	while (!isdigit(c)) c=getchar();
    	while (isdigit(c)) ans=(ans<<3)+(ans<<1)+(c^48),c=getchar();
    	return ans;
    }
    inline void print(lll ans){
    	if (ans>9) print(ans/10);
    	putchar(ans%10+48);
    }
    inline void add(int x,int y,int w){e[++et]=(node){y,w,as[x]},as[x]=et;}
    inline void Push(pair<lll,int>w){
    	heap[++Cnt]=w;
    	rr int x=Cnt;
    	while (x>1){
    		if (heap[x]<heap[x>>1])
    		    swap(heap[x],heap[x>>1]),x>>=1;
    		else return; 
    	}
    }
    inline void Pop(){
    	heap[1]=heap[Cnt--];
    	rr int x=1;
    	while ((x<<1)<=Cnt){
    		rr int y=x<<1;
    		if (y<Cnt&&heap[y+1]<heap[y]) ++y;
    		if (heap[x]>heap[y]) swap(heap[x],heap[y]),x=y;
    		    else return;
    	}
    }
    inline void Dijkstra(int S){
    	heap[++Cnt]=make_pair(0,S);
    	for (rr int i=1;i<=cnt;++i) dis[i]=1e15; dis[S]=0;
    	while (Cnt){
    		rr lll t=heap[1].first; rr int x=heap[1].second;
    		Pop(); if (t!=dis[x]) continue;
    		for (rr int i=as[x];i;i=e[i].next)
    		if (dis[e[i].y]>dis[x]+e[i].w){
    			dis[e[i].y]=dis[x]+e[i].w;
    			Push(make_pair(dis[e[i].y],e[i].y));
    		}
    	}
    }
    inline void build(int &k,int l,int r){
    	if (l==r) {k=l; return;}
    	if (!k) k=++cnt,++cnt;
    	rr int mid=(l+r)>>1;
    	build(ls[k],l,mid);
    	build(rs[k],mid+1,r);
        add(k,ls[k],0),add(k,rs[k],0);
    	if (l==mid) add(ls[k],k^1,0);
    	    else add(ls[k]^1,k^1,0);
    	if (mid+1==r) add(rs[k],k^1,0);
    	    else add(rs[k]^1,k^1,0);
    }
    inline void update(int k,int l,int r,int x,int y,int z,int w){
    	if (l==r){
    		if (w<0) add(l,z,-w);
    		    else add(z,l,w);
    		return;
    	}
    	if (l==x&&r==y){
    		if (w<0) add(k^1,z,-w);
    		    else add(z,k,w);
    	    return;
    	}
    	rr int mid=(l+r)>>1;
    	if (y<=mid) update(ls[k],l,mid,x,y,z,w);
    	else if (x>mid) update(rs[k],mid+1,r,x,y,z,w);
    	    else update(ls[k],l,mid,x,mid,z,w),update(rs[k],mid+1,r,mid+1,y,z,w);
    }
    signed main(){
    	n=iut(),m=iut(),S=iut(),cnt=n;
    	if (!(cnt&1)) ++cnt;
    	build(root,1,n);
    	for (rr int i=1;i<=m;++i)
    	switch (iut()){
    		case 1:{
    			rr int x=iut(),y=iut(),w=iut();
    			add(x,y,w);
    			break;
    		}
    		case 2:{
    			rr int x=iut(),l=iut(),r=iut(),w=iut();
    			if (l==r) add(x,l,w);
    			    else update(root,1,n,l,r,x,w);
    			break;
    		}
    		case 3:{
    			rr int x=iut(),l=iut(),r=iut(),w=iut();
    			if (l==r) add(l,x,w);
    			    else update(root,1,n,l,r,x,-w);
    			break;
    		}
    	} 
    	Dijkstra(S);
    	for (rr int i=1;i<=n;++i){
    		if (dis[i]==1e15) putchar('-'),putchar(49);
    			else print(dis[i]);
    		putchar(i==n?10:32);
    	}
    	return 0;
    }
    
  • 相关阅读:
    数据的艺术
    第十七篇 make的路径搜索综合实践
    第十六篇 make中的路径搜索
    第十五篇 make中的隐式规则概述
    第十四篇 自动生成依赖关系(终结)
    [SDOI2009]HH的项链解题报告
    欧几里德与扩展欧几里德算法的理解、实现与应用
    浅析强连通分量(Tarjan和kosaraju)
    deque-at
    plt.imshow()
  • 原文地址:https://www.cnblogs.com/Spare-No-Effort/p/14602319.html
Copyright © 2011-2022 走看看