数据结构优化建图总结

数据结构优化建图总结

线段树优化建图

把要连的区间拆成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\n",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;
}

后记

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

原文地址:https://www.cnblogs.com/lcyfrog/p/11624758.html

时间: 2024-10-06 00:10:39

数据结构优化建图总结的相关文章

[bzoj3218] a+b problem [最小割+数据结构优化建图]

题面 传送门 思路 最小割 我们首先忽略掉那个奇♂怪的限制,就有一个比较显然的最小割模型: 建立源点$S$和汇点$T$ 对于每个元素$i$建立一个点$i$,连边$<S,i,w[i]>$和$<i,T,b[i]>$ 这样,割掉$<S,i>$边就表示选白色,割掉$<i,T>$边就表示选黑色,那么答案就是$\sum_{i=1}^nb[i]+w[i] - mincut$ 但是现在有一个奇♂怪的限制出来了 奇♂怪的限制 这个限制,是当$i$点黑色,$j<i$点白色

【bzoj3073】[Pa2011]Journeys 线段树优化建图+堆优化Dijkstra

题目描述 Seter建造了一个很大的星球,他准备建造N个国家和无数双向道路.N个国家很快建造好了,用1..N编号,但是他发现道路实在太多了,他要一条条建简直是不可能的!于是他以如下方式建造道路:(a,b),(c,d)表示,对于任意两个国家x,y,如果a<=x<=b,c<=y<=d,那么在xy之间建造一条道路.Seter保证不会有一个国家与自己之间有道路. Seter好不容易建好了所有道路,他现在在位于P号的首都.Seter想知道P号国家到任意一个国家最少需要经过几条道路.当然,Se

Codeforces 787D. Legacy 线段树优化建图+最短路

output standard output Rick and his co-workers have made a new radioactive formula and a lot of bad guys are after them. So Rick wants to give his legacy to Morty before bad guys catch them. There are n planets in their universe numbered from 1 to n.

【题解】SDOI2010所驼门王的宝藏(强连通分量+优化建图)

[题解]SDOI2010所驼门王的宝藏(强连通分量+优化建图) 最开始我想写线段树优化建图的说,数据结构学傻了233 虽然矩阵很大,但是没什么用,真正有用的是那些关键点 考虑关键点的类型: 横走型 竖走型 八连通型 本质上只有两种类型(走一大串/走八连通),我们考虑这样一种建图方法: 对于每一行每一列建立一个点(点权为\(0\)) 对于关键点建立一个点(点权为\(1\)) 然后考虑这样一种建图方式,得到一个有点权无边权图 关键点所在的行与列无偿地向这个关键点连边 横走型的关键点向行连一条边,竖走

【bzoj4276】[ONTAK2015]Bajtman i Okr?g?y Robin 线段树优化建图+费用流

题目描述 有n个强盗,其中第i个强盗会在[a[i],a[i]+1],[a[i]+1,a[i]+2],...,[b[i]-1,b[i]]这么多段长度为1时间中选出一个时间进行抢劫,并计划抢走c[i]元.作为保安,你在每一段长度为1的时间内最多只能制止一个强盗,那么你最多可以挽回多少损失呢? 输入 第一行包含一个正整数n(1<=n<=5000),表示强盗的个数. 接下来n行,每行包含三个正整数a[i],b[i],c[i](1<=a[i]<b[i]<=5000,1<=c[i]

【BZOJ3681】Arietta 树链剖分+可持久化线段树优化建图+网络流

[BZOJ3681]Arietta Description Arietta 的命运与她的妹妹不同,在她的妹妹已经走进学院的时候,她仍然留在山村中.但是她从未停止过和恋人 Velding 的书信往来.一天,她准备去探访他.对着窗外的阳光,临行前她再次弹起了琴.她的琴的发声十分特殊.让我们给一个形式化的定义吧.所有的 n 个音符形成一棵由音符 C ( 1 号节点) 构成的有根树,每一个音符有一个音高 Hi .Arietta 有 m 个力度,第 i 个力度能弹出 Di 节点的子树中,音高在 [Li,R

BZOJ 3218 A+B Problem(最大流 + 主席树优化建图)

题目:A+B Problem 感谢 Nietzsche 在省选紧迫之际花 39' 给我讲这道题. 这题我并没有想出来,感觉又浪费一道好题了. 需要用最小割,建模方式如下(假设若 2 取黑色,1 取白色会使 2 为奇怪方格): 跑一边最大流,求出最小割,用所有的 W + 所有的 B - 最小割,就是答案. 不过,对于每一个结点 2,在寻找像 1 这样(li <= aj <= ri)的结点时,总不能一个一个枚举吧? O(n2) T 飞. 所以,需要用主席树优化一下.线段树优化建图笔记. 代码未完待

【ARC069F】Flags 2-sat+线段树优化建图+二分

Description ? 数轴上有 n 个旗子,第 ii 个可以插在坐标 xi或者 yi,最大化两两旗子之间的最小距离. Input ? 第一行一个整数 N. ? 接下来 N 行每行两个整数 xi,yi Output ? 一个整数表示答案. Sample Input Sample #1 3 1 3 2 5 1 9 Sample #2 5 2 2 2 2 2 2 2 2 2 2 Sample #3 22 93 6440 78 6647 862 11 8306 9689 798 99 801 52

一个神秘的oj2587 你猜是不是dp(线段树优化建图)

哇 这难道不是happiness的翻版题嘛? 从\(S\)向一个点连染成白色的收益 从这个点向\(T\)连染成黑色的收益 对于额外的收益,建一个辅助点,跟区间内的每个点连\(inf\),然后向S/T,连流量为收益 这不就结束了吗? 自信写完,提交 woc!!只有40分? #include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath>