• CF786B Legacy(线段树优化建图+最短路)


    在qbxt某营集体做的

    题解里以及外地OIer基本上都写两颗线段树的

    而我们六安的OIer神TM思维一致——只用一颗线段树,类似于一维分层图的思想,第二层上与第一层相对应的结点的编号是第一层结点编号+NUM,而且貌似比分颗的思维正常一点,因为满足lson=k<<1,rson=k<<1|1,和一般的线段树相似度高。

    至于为什么要分颗或分层,容易想明白树边(辅助边)必须是双向的(因为要用祖先结点的出入信息),但如果不分颗或分层的话求出来最短路不很明显是0了吗QwQ

    所以分层的话父向子应是一层,子向父应在另一层,两层之间通过叶节点相连

    另外关于叶结点的处理问题,YoOXiii和Pride205是把原图第i结点投影到树上第i+n结点(n为原图结点个数)

    这个详见他们的代码(其实我也没仔细研究清楚他们的处理方法),这里不偷了(偷窃犯罪w),要看自己找

    由于我和他们不坐一块,想思路时没有交流,所以我没有这样写,我是把第一层按照一般线段树的编号建,这样容易一点。然后把原图结点直接向叶子结点映射即可(开一个pos数组)(才知道szsz46也是这么写的,原来六安OIer的思维同步性不随空间改变QwQ)

    然后......

    上代码吧

    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<queue>
    #include<iostream>
    #define NUM 1000000
    #define maxn 100005<<5
    //这两个范围要调好 
    #define int long long
    using namespace std;
    typedef long long ll;
    
    inline void input(ll &x){
        ll ans=0,f=1;
        char c=getchar();
        while(c>'9'||c<'0'){
            if(c=='-')f=-1;
            c=getchar();
        }
        while(c>='0'&&c<='9'){
            ans=ans*10+c-48;
            c=getchar();
        }
        x=ans*f;
    }
    
    inline void output(ll x){
        if(x<0)x=-x,putchar('-');
        if(x>9)output(x/10);
        putchar(x%10+48);
    }
    
    inline void writeln(ll x){
        output(x);
        putchar('
    ');
    }
    
    int n,m,s,head[maxn],c[maxn],pos[maxn],vis[maxn],dis[maxn],cnt;
    
    //pos:题中结点在树上的编号 
    
    struct edge{
    	int v,w,next;
    }e[maxn];
    
    struct node{
    	int dis,u;
    	bool operator<(const node &x)const{return x.dis<dis;}
    };
    
    inline void add(int u,int v,int w){
    	e[++cnt].v=v;
    	e[cnt].w=w;
    	e[cnt].next=head[u];
    	head[u]=cnt;
    //	cout<<u<<' '<<v<<' '<<w<<endl;
    }
    
    inline void build(int k,int l,int r){
    	if(l==r){
    		pos[l]=k;
    		add(k+NUM,k,0);
    		add(k,k+NUM,0);
    		return;
    	}
    	int mid=(l+r)>>1;
    	build(k<<1,l,mid);
    	build(k<<1|1,mid+1,r);
    	add(k<<1,k,0);
    	add(k<<1|1,k,0);
    	add(k+NUM,(k<<1)+NUM,0);//调了一个小时:加括号;在括号外加NUM而不是给k加NUM 
    	add(k+NUM,(k<<1|1)+NUM,0);
    }
    
    inline void add(int k,int l,int r,int xl,int xr,int from,int w,int opt){
    	if(xl<=l&&r<=xr){
    		if(opt==2)add(from,k+NUM,w);
    		else if(opt==3)add(k,from,w);
    		return;
    	}
    	int mid=(l+r)>>1;
    	if(xl<=mid)add(k<<1,l,mid,xl,xr,from,w,opt);
    	if(xr>=mid+1)add(k<<1|1,mid+1,r,xl,xr,from,w,opt);
    }
    
    priority_queue<node> q;
    
    inline void dijkstra(){
    	s=pos[s];
    	q.push((node){0,s});
    	dis[s]=0;
    	while(!q.empty()){
    		int x=q.top().u;
    		q.pop();
    		if(vis[x])continue;
    		vis[x]=1;
    		for(int i=head[x];i!=-1;i=e[i].next){
    			int y=e[i].v;
    			if(!vis[y]&&dis[y]>dis[x]+e[i].w){
    				dis[y]=dis[x]+e[i].w;
    				q.push((node){dis[y],y});//想不到吧,这一行打错使我调了半个小时 
    			}
    		}
    	}
    	s<<=1;
    	if(s>=1)dijkstra();
    }
    
    signed main(){
    	memset(head,-1,sizeof(head));
    	memset(dis,127,sizeof(dis));
    	memset(vis,0,sizeof(vis));
    	input(n);input(m);input(s);
    	build(1,1,n);
    	for(int i=1;i<=m;i++){
    		int opt;
    		input(opt);
    		if(opt==1){
    			int u,v,w;
    			input(u);input(v);input(w);
    			add(pos[u],pos[v],w);
    		}
    		else if(opt==2){
    			int u,l,r,w;
    			input(u);input(l);input(r);input(w);
    			add(1,1,n,l,r,pos[u],w,opt);
    		}
    		else if(opt==3){
    			int u,l,r,w;
    			input(u);input(l);input(r);input(w);
    			add(1,1,n,l,r,pos[u],w,opt);
    		}
    	}
    	dijkstra();
    //	for(int i=1;i<=4*n;i++)cout<<i<<' '<<dis[i]<<endl;
    	for(int i=1;i<=n;i++)output(dis[pos[i]]<=1e15?dis[pos[i]]:-1),putchar(' ');
    }
    
    
  • 相关阅读:
    星辰小队针对于软件“星遇”的10天冲刺——第8天
    星辰小队针对于软件“星遇”的10天冲刺——第7天
    周周总结——时时更新(第4学期,第11周)
    星辰小队针对于软件“星遇”的10天冲刺——第6天
    星辰小队针对于软件“星遇”的10天冲刺——第5天
    对于文章的字母、单词、短语,(无用词表)的检索Java代码实现
    星辰小队针对于软件“星遇”的10天冲刺——第4天
    图片保存到相册
    心情不好
    NSString和data转换
  • 原文地址:https://www.cnblogs.com/Y15BeTa/p/11318060.html
Copyright © 2020-2023  润新知