线段树优化建图 学习笔记
线段树优化建图是用于给区间建边的一种较快的方式,可以把区间连向单点的时间复杂度变为 \(O(\log n)\)。
思路
我们回顾一下线段树的结构,是不是有若干个区间,每个区间是 \([l,r]\)。
当我们进行点对区间建边的时候,我们可以把建边的区间拆分到一个类似线段树的结构上,将点一一和线段树区间中的每个点相连,这样只需要连 \(O(\log n)\) 条边。
但是如果我们要把点连向区间,同时还要把区间连向点的话,在一棵树上就不是很能完成。
于是我们建立两棵树,一颗从上往下,父节点和子节点建一条边权为 \(0\) 的边,一颗从下往上,子节点对父节点建一条边权为 \(0\) 的边。同时在两棵树相对应的叶子节点建一条边权为 \(0\) 的边。在连边时,如果是点连向区间,我们就从第二棵树的节点连向第一棵树的对应节点,否则将第一棵树连向第二棵树。
那么我们就写完了。
代码
拿 CF768B 举例。
codeforces:https://codeforces.com/contest/786/submission/314975891
点击查看代码
#include<bits/stdc++.h>
#define int ll
#define pii pair<int,int>
#define pll pair<long long,long long>
#define ll long long
#define i128 __int128
#define mem(a,b) memset((a),(b),sizeof(a))
#define m0(a) memset((a),0,sizeof(a))
#define m1(a) memset(a,-1,sizeof(a))
#define lb(x) ((x)&-(x))
#define lc(x) ((x)<<1)
#define rc(x) (((x)<<1)|1)
#define pb(G,x) (G).push_back((x))
#define For(a,b,c) for(int a=(b);a<=(c);a++)
#define Rep(a,b,c) for(int a=(b);a>=(c);a--)
#define in1(a) a=read()
#define in2(a,b) a=read(), b=read()
#define in3(a,b,c) a=read(), b=read(), c=read()
#define in4(a,b,c,d) a=read(), b=read(), c=read(), d=read()
#define fst first
#define scd second
#define dbg puts("IAKIOI")
using namespace std;
int read() {
int x=0,f=1; char c=getchar();
for(;c<'0'||c>'9';c=getchar()) f=(c=='-'?-1:1);
for(;c<='9'&&c>='0';c=getchar()) x=(x<<1)+(x<<3)+(c^48);
return x*f;
}
void write(int x) { if(x>=10) write(x/10); putchar('0'+x%10); }
const int mod = 998244353;
int qpo(int a,int b) {int res=1; for(;b;b>>=1,a=(a*a)%mod) if(b&1) res=res*a%mod; return res; }
int inv(int a) {return qpo(a,mod-2); }
#define maxn 200050
int n,m,s;
const int del=5e5;
vector<pii > G[maxn<<3];
bool vis[maxn<<3];
int bott[maxn];
void ade(int u,int v,int w) {
G[u].push_back({v,w});
// cout<<"edge:{"<<u<<' '<<v<<' '<<w<<"}\n";
}
void build(int idx,int l,int r) {
if(l==r) {
bott[l]=idx;
ade(idx,idx+del,0);
return ;
}
ade(idx,lc(idx),0);
ade(idx,rc(idx),0);
ade(lc(idx)+del,idx+del,0);
ade(rc(idx)+del,idx+del,0);
int mid=l+r>>1;
build(lc(idx),l,mid);
build(rc(idx),mid+1,r);
}
void add(int idx,int l,int r,int L,int R,int v,int w,int opt) {
if(L<=l&&r<=R) {
if(opt==0) ade(del+v,idx,w);
else ade(del+idx,v,w);
return ;
}
int mid=l+r>>1;
if(L<=mid) add(lc(idx),l,mid,L,R,v,w,opt);
if(R>mid) add(rc(idx),mid+1,r,L,R,v,w,opt);
}
int dis[maxn<<3];
void work() {
in3(n,m,s);
build(1,1,n);
For(i,1,m) {
int opt,v,u,l,r,w;
in2(opt,v);
if(opt!=1) in2(l,r);
else in1(u);
in1(w);
if(opt==1) ade(bott[v],bott[u],w);
else add(1,1,n,l,r,bott[v],w,opt%2);
}
priority_queue<pii,vector<pii >,greater<pii > >q;
while(!q.empty()) q.pop();
q.push({0,bott[s]});
mem(dis,0x3f); dis[bott[s]]=0;
while(!q.empty()) {
auto [qwq,u] =q.top(); q.pop();
if(vis[u]) continue;
// cout<<u<<'\n';
vis[u]=1;
for(auto [v,d]:G[u]) if(!vis[v]&&dis[u]+d<dis[v]) {
dis[v]=dis[u]+d;
q.push({dis[v],v});
}
}
For(i,1,n) cout<<(dis[bott[i]]>=4557430888798830399?-1:dis[bott[i]])<<' ';
}
signed main() {
// freopen("data.in","r",stdin);
// freopen("myans.out","w",stdout);
// ios::sync_with_stdio(false);
// cin.tie(0); cout.tie(0);
double stt=clock();
int _=1;
// _=read();
// cin>>_;
For(i,1,_) {
work();
}
cerr<<"\nTotal Time is:"<<(clock()-stt)*1.0/1000<<" second(s)."<<'\n';
return 0;
}
本文来自博客园,作者:coding_goat_qwq,转载请注明原文链接:https://www.cnblogs.com/CodingGoat/p/18820938

浙公网安备 33010602011771号