线段树优化建树 CF786B

看到区间操作想到用线段树优化建树,建一棵外向树一棵内向树,用线段树点代表整个区间内的所有点。

大佬的图

https://www.luogu.com.cn/article/ypjofq71

从树上找节点然后连边就可以,最后跑个dijktra就完成了。

我一次就过样例了,改了几次内存就过了这题,太好了!!!

#include <bits/stdc++.h>
#define ll long long
#define int ll
#define ls p<<1
#define rs p<<1|1
#define re register
#define pb push_back
#define pir pair<int,int>
#define f(a,x,i) for(int i=a;i<=x;i++)
#define fr(a,x,i) for(int i=a;i>=x;i--)
#define lb(x) x&(-x);
using namespace std;
const int N=1e6+10;
const int M=8e6+10;
const int mod=1e9+7;
int n,q,s;
int cnt;
struct sss{
int v,w;
};
vector<sss> a[N];
struct ss{
int l,r,id;
}t1[N<<1],t2[N<<1];
int top1,top2;
int build1(int p,int l,int r){
if(l==r){
return t1[l].id;
}
t1[p].id=p;
int mid=(l+r)>>1;
t1[p].l=build1(++cnt,l,mid);
t1[p].r=build1(++cnt,mid+1,r);
a[p].push_back({t1[p].l,0});
a[p].push_back({t1[p].r,0});
return p;
}
int build2(int p,int l,int r){
if(l==r){
return t2[l].id;
}
t2[p].id=p;
int mid=(l+r)>>1;
t2[p].l=build2(++cnt,l,mid);
t2[p].r=build2(++cnt,mid+1,r);
a[t2[p].l].push_back({p,0});
a[t2[p].r].push_back({p,0});
return p;
}
void change1(int p,int pl,int pr,int l,int r,int x,int w){
if(pl>=l&&pr<=r){
a[x].push_back({p,w});
return;
}
int mid=(pl+pr)>>1;
if(l<=mid) change1(t1[p].l,pl,mid,l,r,x,w);
if(r>mid) change1(t1[p].r,mid+1,pr,l,r,x,w);
}
void change2(int p,int pl,int pr,int l,int r,int x,int w){
if(pl>=l&&pr<=r){
a[p].push_back({x,w});
return;
}
int mid=(pl+pr)>>1;
if(l<=mid) change2(t2[p].l,pl,mid,l,r,x,w);
if(r>mid) change2(t2[p].r,mid+1,pr,l,r,x,w);
}
int dis[N];
int vis[N];
void dijkstra(int s){
for(int i=1;i<=cnt;i++) dis[i]=1e18;
dis[s]=0;
priority_queue<pir,vector<pir>,greater<pir> > q;
q.push({0,s});
while(!q.empty()){
int u=q.top().second;
q.pop();
if(vis[u]) continue;
vis[u]=1;
for(auto i:a[u]){
int v=i.v;
int w=i.w;
if(dis[v]>dis[u]+w){
dis[v]=dis[u]+w;
q.push({dis[v],v});
}
}
}
}
signed main(){
ios::sync_with_stdio(0);
cin.tie(nullptr);
cin>>n>>q>>s;
for(int i=1;i<=n;i++){
t1[i].id=i;
t2[i].id=i+n;
a[i].push_back({i+n,0});
a[i+n].push_back({i,0});
}
cnt=2*n;
top1=build1(++cnt,1,n);
top2=build2(++cnt,1,n);
for(int i=1;i<=q;i++){
int op,u,v,w,l,r;
cin>>op;
if(op==1){
cin>>u>>v>>w;
a[u].push_back({v,w});
}
else if(op==2){
cin>>u>>l>>r>>w;
change1(top1,1,n,l,r,u+n,w);
}
else{
cin>>u>>l>>r>>w;
change2(top2,1,n,l,r,u,w);
}
}
dijkstra(s);
for(int i=1;i<=n;i++){
if(dis[i]==1e18) cout<<"-1 ";
else cout<<dis[i]<<" ";
}
return 0;
}
posted @   sad_lin  阅读(4)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· winform 绘制太阳,地球,月球 运作规律
· TypeScript + Deepseek 打造卜卦网站:技术与玄学的结合
· AI 智能体引爆开源社区「GitHub 热点速览」
· Manus的开源复刻OpenManus初探
· 写一个简单的SQL生成工具
点击右上角即可分享
微信分享提示