zoukankan      html  css  js  c++  java
  • 数据结构优化建图总结

    数据结构优化建图总结

    线段树优化建图

    把要连的区间拆成log个点(线段树上的点)连要要连的点上,如果是区间连区间可以建(log^2) 条边

    注意,区间连进去和连出来的边顺序不一样,线段树建法也不同

    1. 单点连区间(连进去) 由于本质是链接所有根节点,线段树父亲向儿子连零边,保证能到达
    2. 区间连单点(连出去)由于所有根节点连这个点,线段树儿子向父亲连零边,能够连出去

    此时就需要两颗线段树

    例题:CF786B

    我会告诉你们用大根堆维护dijkstra还过了前四个点 改longlong看线段树看了半天吗(真长)

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #include<vector>
    #define inf 99264435330203ll
    using namespace std;
    long long read(){
    	long long x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x;
    }
    long long n,m,s,r1,r2;
    const long long N = 2000001;
    long long ls[N<<1],rs[N<<1],tot;
    struct node{
    	long long v,nex,w;
    }edge[N<<1];
    long long head[N<<1],top;
    void add(long long u,long long v,long long w){
    	edge[++top].v=v;
    	edge[top].nex=head[u];
    	edge[top].w=w;
    	head[u]=top;
    }
    void build1(long long &now,long long l,long long r){
    	if(l==r){
    		now=l;
    		return;
    	}
    	now=++tot;
    	long long mid=(l+r)>>1;
    	build1(ls[now],l,mid);
    	build1(rs[now],mid+1,r);
    	add(now,ls[now],0);
    	add(now,rs[now],0);
    }
    void build2(long long &now,long long l,long long r){
    	if(l==r){
    		now=l;
    		return;
    	}
    	now=++tot;
    	long long mid=(l+r)>>1;
    	build2(ls[now],l,mid);
    	build2(rs[now],mid+1,r);
    	add(ls[now],now,0);
    	add(rs[now],now,0);
    }
    void modify1(long long now,long long l,long long r,long long ql,long long qr,long long u,long long w){
    	if(ql<=l&&r<=qr){
    		add(u,now,w);
    		return;
    	}
    	long long mid=(l+r)>>1;
    	if(ql<=mid) modify1(ls[now],l,mid,ql,qr,u,w);
    	if(mid<qr) modify1(rs[now],mid+1,r,ql,qr,u,w);
    }
    void modify2(long long now,long long l,long long r,long long ql,long long qr,long long u,long long w){
    	if(ql<=l&&r<=qr){
    		add(now,u,w);
    		return;
    	}
    	long long mid=(l+r)>>1;
    	if(ql<=mid) modify2(ls[now],l,mid,ql,qr,u,w);
    	if(mid<qr) modify2(rs[now],mid+1,r,ql,qr,u,w);
    }
    long long dis[N<<1],vis[N<<1];
    struct tp{
    	long long p,w;
    };
    struct cmp{
    	bool operator()(tp a,tp b){
    		return a.w>b.w;
    	}
    };
    long long ans=0;
    void dijkstra(long long s){
    	priority_queue<tp,vector<tp>,cmp>q;
    	for(long long i=1;i<=tot;i++){
    		dis[i]=inf;vis[i]=0; 
    	}
    	dis[s]=0;
    	tp f;f.p=s;f.w=0;
    	q.push(f);
    	while(!q.empty()){
            tp nt=q.top();
            q.pop();
            long long now=nt.p;
            if(vis[now]) continue;
            else vis[now]=1;
            for(int i=head[now];i;i=edge[i].nex){
            	long long nex=edge[i].v;
            	if(dis[nex]>dis[now]+edge[i].w){
            		dis[nex]=dis[now]+edge[i].w;
            		if(!vis[nex]){
            			tp to_push;
            			to_push.p=nex;
            			to_push.w=dis[nex];
            			q.push(to_push);
            		}
            	}
            }
        }
    	for(long long i=1;i<=n;i++){
    		printf("%lld ",dis[i]>=inf?-1:dis[i]);
    	}
    }
    int main(){
    	n=read(),m=read(),s=read();
    	tot=n;
    	build1(r1,1,n);
    	build2(r2,1,n);
    	for(long long i=1;i<=m;i++){
    		long long opt=read();
    		if(opt==1){
    			long long v=read(),u=read(),w=read();
    			add(v,u,w);
    		}else if(opt==2){
    			long long v=read(),l=read(),r=read(),w=read();
    			modify1(r1,1,n,l,r,v,w);
    		}else{
    			long long v=read(),l=read(),r=read(),w=read();
    			modify2(r2,1,n,l,r,v,w);
    		}
    	}
    	dijkstra(s);
    	return 0;
    }
    

    K-D 树优化建图

    NOI 2019考到了所以写一写

    竟然1A了。。。(可能是之前一些KDT的题调了好久所以比较熟悉

    思路跟线段树的差不多,这题不过空间开不下,所以考虑不保存边

    考虑dijkstra算法中每个点只能作为中间节点松弛连的节点一次(vis)

    于是建边的复杂度就跟每次直接K-D树上查询复杂度一样啦

    具体来说,

    1. 如果当前点是原来的点,直接上树查询并松弛

    2. 如果是树上的点,它不可能再向树上区间连边,只连向它的左右儿子和对应的原点

    码量也不是很大

    #include<iostream>
    #include<cstdio>
    #include<algorithm>
    #include<cstring>
    #include<queue>
    #define inf 1926081700;
    using namespace std;
    int read(){
    	int x=0,pos=1;char ch=getchar();
    	for(;!isdigit(ch);ch=getchar()) if(ch=='-') pos=0;
    	for(;isdigit(ch);ch=getchar()) x=(x<<1)+(x<<3)+ch-'0';
    	return pos?x:-x;
    } 
    const int N = 75001;
    struct point{
    	int x[2],ori;
    }p[N<<1];
    struct node{
    	int mx[2],mi[2],sz,ord;
    	point c;
    }t[N<<1];
    int ls[N<<1],rs[N<<1];
    int n,m,w,h,tot,D;
    int operator < (point a,point b){
    	return a.x[D]<b.x[D];
    }
    int operator > (point a,point b){
    	return a.x[D]>b.x[D];
    }
    inline void push_up(int now){
    	int l=ls[now],r=rs[now];
    	t[now].sz=t[l].sz+t[r].sz+1;
    	t[now].mi[0]=t[now].mx[0]=t[now].c.x[0];t[now].mi[1]=t[now].mx[1]=t[now].c.x[1];
    	if(l) t[now].mi[0]=min(t[now].mi[0],t[l].mi[0]),t[now].mi[1]=min(t[now].mi[1],t[l].mi[1]),t[now].mx[0]=max(t[now].mx[0],t[l].mx[0]),t[now].mx[1]=max(t[now].mx[1],t[l].mx[1]);
    	if(r) t[now].mi[0]=min(t[now].mi[0],t[r].mi[0]),t[now].mi[1]=min(t[now].mi[1],t[r].mi[1]),t[now].mx[0]=max(t[now].mx[0],t[r].mx[0]),t[now].mx[1]=max(t[now].mx[1],t[r].mx[1]);
    }
    inline void build(int &now,int l,int r,int d){
    	if(l>r) return; 
    	now=++tot;int mid=(l+r)>>1;
    	D=d;nth_element(p+l,p+mid,p+r+1);t[now].c=p[mid];t[now].ord=p[mid].ori;
    	build(ls[now],l,mid-1,d^1);build(rs[now],mid+1,r,d^1);
    	push_up(now);
    } 
    struct sqr{
    	int x1,x2,y1,y2,w;
    }qu[N<<1];
    struct graph{
    	int v,nex;
    }edge[N<<1];
    int tope=0,head[N],dis[N<<1],vis[N<<1],rt;
    void add(int u,int v){
    	edge[++tope].v=v;
    	edge[tope].nex=head[u];
    	head[u]=tope;
    }
    struct type{
    	int pt,w;
    };
    struct cmp{
    	int operator()(type a,type b){
    		return a.w>b.w;
    	}
    };
    priority_queue<type,vector<type>,cmp> q;
    inline type mk(int a,int b){
    	type nw;nw.pt=a,nw.w=b;return nw;
    }
    inline void relax(int u,int v,int w){
    	if(dis[v]>dis[u]+w){
    		dis[v]=dis[u]+w;
    		if(!vis[v]){
    			q.push(mk(v,dis[v]));
    		}
    	}
    }
    inline int totalin(int now,sqr tp){
    	return (t[now].mi[0]>=tp.x1&&t[now].mx[0]<=tp.x2&&t[now].mi[1]>=tp.y1&&t[now].mx[1]<=tp.y2); 
    }
    inline int totalout(int now,sqr tp){
    	return (t[now].mx[0]<tp.x1||t[now].mi[0]>tp.x2||t[now].mx[1]<tp.y1||t[now].mi[1]>tp.y2); 
    }
    inline int ptin(point now,sqr tp){
    	return (now.x[0]>=tp.x1&&now.x[0]<=tp.x2&&now.x[1]>=tp.y1&&now.x[1]<=tp.y2); 
    }
    inline void query(int now,sqr tp,int u){
    	if(totalin(now,tp)){
    		relax(u,now,tp.w);
    		return;
    	}
    	if(ptin(t[now].c,tp)) relax(u,t[now].ord,tp.w);
    	int l=ls[now],r=rs[now];
    	if(!totalout(l,tp)) query(l,tp,u);
    	if(!totalout(r,tp)) query(r,tp,u); 
    }
    inline void dijkstra(){
    	q.push(mk(1,0));dis[1]=0;
    	for(int i=2;i<=tot;i++){
    		dis[i]=inf;
    	}
    	while(!q.empty()){
    		int now=q.top().pt;q.pop();
    		if(vis[now]) continue;else vis[now]=1;
    		if(now<=n){
    			for(int i=head[now];i;i=edge[i].nex){
    				int v=edge[i].v;
    				query(rt,qu[v],now);
    			}
    		}else{
    			relax(now,ls[now],0);
    			relax(now,rs[now],0);
    			relax(now,t[now].ord,0); 
    		}
    	}
    	for(int i=2;i<=n;i++){
    		printf("%d
    ",dis[i]);
    	}
    }
    int main(){
    	n=read(),m=read(),w=read(),h=read();
    	for(int i=1;i<=n;i++){
    		p[i].x[0]=read(),p[i].x[1]=read(),p[i].ori=i;
    	}
    	tot=n;
    	build(rt,1,n,1);
    	for(int i=1;i<=m;i++){
    		int u=read();
    		qu[i].w=read(),qu[i].x1=read(),qu[i].x2=read(),qu[i].y1=read(),qu[i].y2=read();
    		add(u,i);
    	}
    	dijkstra();
    	return 0;
    }
    

    后记

    没有听说其他优化建边的了。。。应该就这两个吧

  • 相关阅读:
    javascript学习随笔《四》
    google卫星地图地图矫正
    sharpmap v2学习研究(二)
    c#中的位运算,逻辑非~,逻辑与&,逻辑或|,逻辑异或^,逻辑左移<<,逻辑右移>>
    如何判断一个form是否被关闭
    List转DataTable(反射)
    c#位运算
    解决ASP.NET中的各种乱码问题 转自 Fish Li
    IHE自测MESA环境搭建详解
    HTTP协议请求 转
  • 原文地址:https://www.cnblogs.com/lcyfrog/p/11624758.html
Copyright © 2011-2022 走看看