CF786B Legacy 线段树优化建图

问题描述

CF786B

LG-CF786B


题解

线段树优化建图

线段树的一个区间结点代表 \([l,r]\) 区间点。

然后建立区间点的时候就在线段树上建边,有效减少点的个数,从而提高时空效率。

优质题解传送门


\(\mathrm{Code}\)

#include<bits/stdc++.h>
using namespace std;

#define int long long

template <typename Tp>
void read(Tp &x){
    x=0;char ch=1;int fh;
    while(ch!='-'&&(ch>'9'||ch<'0')) ch=getchar();
    if(ch=='-') ch=getchar(),fh=-1;
    else fh=1;
    while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+ch-'0',ch=getchar();
    x*=fh;
}

const int maxn=100100;
int INF=0x3f3f3f3f3f3f3f3fll;

#define pii(x,y) make_pair(x,y)

#define mid ((l+r)>>1)
#define lfc (x<<1)
#define rgc ((x<<1)|1)

vector < pair < int , int > > e[maxn*10];
int n,T,S;
int cnt,out[maxn<<2],in[maxn<<2];

void build(int x,int l,int r){
    if(l==r){
        out[x]=in[x]=l;return;
    }
    build(lfc,l,mid);build(rgc,mid+1,r);
    out[x]=++cnt,in[x]=++cnt;
    e[out[lfc]].push_back(pii(out[x],0));
    e[out[rgc]].push_back(pii(out[x],0));
    e[in[x]].push_back(pii(in[lfc],0));
    e[in[x]].push_back(pii(in[rgc],0));
}

int L,R,st,val;

void change_in(int x,int l,int r){
    if(L<=l&&r<=R){
        e[st].push_back(pii(in[x],val));return;
    }
    if(r<L||R<l) return;
    change_in(lfc,l,mid);change_in(rgc,mid+1,r);
}

void change_out(int x,int l,int r){
    if(L<=l&&r<=R){
        e[out[x]].push_back(pii(st,val));return;
    }
    if(r<L||R<l) return;
    change_out(lfc,l,mid);change_out(rgc,mid+1,r);
}

int dis[maxn*10];
priority_queue< pair <int,int> > q;

bool vis[maxn*10];

void dijkstra(){
    memset(dis,0x3f,sizeof(dis));dis[S]=0;
    q.push(pii(0,S));
    while(!q.empty()){
        int x=q.top().second;q.pop();
        if(vis[x]) continue;
        vis[x]=1;
        for(auto &i:e[x]){
            int y=i.first;
            if(y==0) continue;
            if(i.second+dis[x]<dis[y]){
                dis[y]=dis[x]+i.second;
                q.push(pii(-dis[y],y));
            }
        }
    }
}

signed main(){
    read(n);read(T);read(S);
    cnt=n;build(1,1,n);
    while(T--){
        int op;read(op);
        if(op==1){
            int aa,bb,cc;read(aa);read(bb);read(cc);
            e[aa].push_back(pii(bb,cc));
        }
        else if(op==2){
            int aa,bb,cc,dd;read(aa);read(bb);read(cc);read(dd);
            L=bb,R=cc,st=aa,val=dd;change_in(1,1,n);
        }
        else{
            int aa,bb,cc,dd;read(aa);read(bb);read(cc);read(dd);
            L=bb,R=cc,st=aa,val=dd;change_out(1,1,n);
        }
    }
    dijkstra();
    for(int i=1;i<=n;i++){
        printf("%lld%c",(dis[i]==INF)?-1:dis[i]," \n"[i==n]);
    }
    return 0;
}

原文地址:https://www.cnblogs.com/liubainian/p/11801602.html

时间: 2024-11-07 22:29:12

CF786B Legacy 线段树优化建图的相关文章

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.

【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]

【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

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

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

【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>

机房测试5:reverse(bfs+set 或 线段树优化建图)

题目: 分析: 首先画样例分析一下,会发现如果要求一个位置要多少次翻转,就将这个位置向与它关联的点连边(关联点指的是可能与它值互换的位置),一直连到起点为止,连边的次数即为它所需步数. 所以转换成求单源最短路,因为边权为1,可以用bfs. 但是这道题n的范围很大,刚刚的做法是n*k的,考虑优化. 法1:在建图上优化 题目要求的是区间翻转,所以也对应着相关性质:每个点连边一定是都连的奇数点或偶数点(画图可知),且这些奇数偶数点都对应着一段连续的区间. 如果可以将点向点连边优化成点向区间连边,复杂度

bzoj5017 [Snoi2017]炸弹 (线段树优化建图+)tarjan 缩点+拓扑排序

题目传送门 https://lydsy.com/JudgeOnline/problem.php?id=5017 题解 这个题目方法挺多的. 线段树优化建图 线段树优化建图的做法应该挺显然的,一个炸弹能够引爆的炸弹的显然应该是一个区间里面的,直接对这个区间进行线段树优化建图. 这样可以得到一个带环图,缩点以后这个炸弹能够炸到的炸弹就是从这个点能够走到的点. 但是这个不太好做,不过可以发现最终的炸弹也是一个区间,所以可以通过缩点后的 DAG 来求出左右端点. 时间复杂度 \(O(n\log n)\)

CF786B Legacy(线段树优化建图)

题意 有n个点,q个询问,每次询问有一种操作.操作1:u→[l,r](即u到l,l+1,l+2,...,r距离均为w)的距离为w:操作2:[l,r]→u的距离为w:操作3:u到v的距离为w:求起点到其他点的最短距离,到达不了输出-1. 题解 线段树骚操作,线段树优化建图. 其实提到可以这么操作后,实现还是很好想的. 建两颗线段树,一颗连进边,一颗连出边. 1 #include<iostream> 2 #include<cstdio> 3 #include<cmath>