首页 > 其他分享 >线段树优化建图

线段树优化建图

时间:2024-08-09 21:40:08浏览次数:11  
标签:lc int 线段 add read 建图 rc 优化 op

今天写了道线段树优化建图的板子题,感觉学算法的还是要记录下来,将来方便复习也算是对竞赛生涯的一种回忆

http://codeforces.com/problemset/problem/786/B,洛谷评级还是省选,如果是比赛现场想出来确实厉害,但是现在嘛,已经是时代眼泪了

归纳下特点:和区间有关的图论问题

直接上代码讲解:

我主要是采取了动态开点线段树与dijkstra最段路算法

#include<iostream> #include<cstring> #include<queue> using namespace std; #define int long long int read(){     int f = 1, x = 0;     char ch = getchar();     while(ch < '0' || ch > '9'){         if(ch == '-')   f = -1;         ch = getchar();     }     while(ch >= '0' && ch <= '9'){         x = (x << 3) + (x << 1) + (ch ^ 48);         ch = getchar();     }     return f * x; }//这是一个常见的快读模板,有点是作为int返回类型可以实现类似python的操作(没怎么学过,大概),缺点是面对以持续读入为条件不合适 const int N = 3e5 + 3;//2棵线段树尾部相连,叶子数为1e5的图形大概有3e5 - 2个点,联想双端广搜的图
struct semgtr{     int lc, rc;     #define lc(x) tr[x].lc//lc即left child,rc同理
    #define rc(x) tr[x].rc//记录一个小知识,define运算的话最好打括号,因为只是关键字的替换所以运算顺序你懂的,养成写成函数的习惯也不错 }tr[20 * N];//理论上点数N就行,但是实际RE洛谷老哥建议开大点,空间足,确实这种数据结构优化的题空间会给的很足我就都开20 * N了
int idx, h[3 * N], e[20 * N], ne[20 * N], w[20 * N], tot, inr, outr, d[N * 3];//关于边数,我虽然说了可以开大点,但是为了确保下限我还是算了下,众所周知,线段树最多会把查询的区间划分成loglen,然后这题n,q范围又一样,所以边数大概是qlogN,然后log不会超过20,所以直接设的20,总之空间够你就开大点
void add(int a, int b,int c){     e[idx] = b;     ne[idx] = h[a];     w[idx] = c;     h[a] = idx++; }//平平无奇邻接表,之前看过一本书说写成结构体会更优,但是吧。个人认为小区别,按习惯吧 void build(int &p, int l, int r, bool op){//op是表示在建入树还是出树,虽然这里画图会好理解,但是我一直是脑测玩家,相信未来的我能模拟出图,你就想象一个点要去你已经建好的菱形(2棵二叉树拼成)里了,入树就是你顺着箭头去到一个节点,然后这个节点的去路是它的子节点,否则,就是它的子节点能顺着箭头走到你,即出树
    if(l == r){         p = l;         return;     }     p = ++tot;//这就是动态开点,按下面的build无论是lc还是rc走到这都是0,如果你不会动态开点(很好学)或者懒得学直接普通线段树堆式存储也行,看一个同学就是这样写的     int mid = (l + r) >> 1;     build(lc(p), l, mid, op);     build(rc(p), mid + 1, r, op);     if(!op){         add(lc(p), p, 0);         add(rc(p), p, 0);     }     else{         add(p, lc(p), 0);         add(p, rc(p), 0);     } } void modify(int &p, int l, int r, int L, int R, int u, int k, bool flag){//同样的,用flag标记是往哪棵树建边,其实还有一个办法你像并查集的扩展域一样加一个大常数来区分,前面 * flag也行
    if(L <= l && r <= R){         flag ? add(u, p, k) : add(p, u, k);         return;     }     int mid = (l + r) >> 1;     if(L <= mid) modify(lc(p), l, mid, L, R, u, k, flag);     if(R > mid)  modify(rc(p), mid + 1, r, L, R, u, k, flag); } bool vis[N * 3];//也是开大了感觉 void dijstra(int s){     memset(d, 0x3f3f3f, sizeof d);//初值能大别小     d[s] = 0;     priority_queue<pair<int, int> > q;     q.push({0, s});     while(!q.empty()){         int u = q.top().second;         q.pop();         if(vis[u])  continue;         vis[u] = true;         for(int i = h[u]; i != -1; i = ne[i]){             int v = e[i];             if(!vis[v] && d[v] > d[u] + w[i]){                 d[v] = d[u] + w[i];                 q.push({-d[v], v});             }         }     } }//板子 signed main(){     memset(h, -1, sizeof h);     int n = read(), m = read(), s = read();     tot = n;//前n个点就是叶子     build(inr, 1, n, 1);     build(outr, 1, n, 0);//分别记一下入树和出树的节点编号     while(m--){         int op = read();         if(op == 1){             int u = read(), v = read();             add(u, v, read());         }         else{             int p = read(), l = read(), r = read(), cost = read();             modify(op == 2 ? inr : outr, 1, n, l, r, p, cost, op == 2);         }     }     dijstra(s);     for(int i = 1; i <= n; i++)  printf("%lld ",d[i] != d[0] ? d[i] : -1);//按我的写法从1开始编号d[0]就是不变,同理,和她相同的距离节点就说明到不了,按题目输出-1     return 0; }

标签:lc,int,线段,add,read,建图,rc,优化,op
From: https://www.cnblogs.com/tingzhimian/p/18351536

相关文章

  • 刍议线段树 2 (区间修改,区间查询)
    线段树\(2\)接上一讲https://www.cnblogs.com/yingxilin/p/18350988(没看的同学们可以先看这篇)上一讲里我们已经介绍了单点修改,区间查询的线段树了。在这一讲里,我们开始学习支持区间修改,区间查询的线段树。考虑之前的做法,之前的查询区间会被分为\(O(logn)\),从而求解,但因为......
  • 线段树维护区间方差
    线段树维护区间方差方差区间方差还教室解题思路:利用线段树维护\(a_i\)与\(a_i^2\)\((1\leqi\leqn)\)两个数列,然后使用一个\(lazytag\)来记录是否进行了区间加,最后输出方差的时候使用$$s^2=\sum\limits_{i=1}^n(a_i-\overlinea)^2=(\sum\limits_{i=1}......
  • 洛谷 P3870 开关之线段树板子
    洛谷P3870题解传送锚点摸鱼环节[TJOI2009]开关题目描述现有\(n\)盏灯排成一排,从左到右依次编号为:\(1\),\(2\),……,\(n\)。然后依次执行\(m\)项操作。操作分为两种:指定一个区间\([a,b]\),然后改变编号在这个区间内的灯的状态(把开着的灯关上,关着的灯打开);指定一个区间......
  • 8.9 线段树板子+三分补题+三维的bfs
    nowcoder训练区间线段树板子题,我们只需要把区间每一个点设置成1,然后修改的时候直接改点,然后查区间就行线段树维护最大字段和/01串最大连续1的个数模板题。把白色和黑色看成1/0两个数就行了。#include<bits/stdc++.h>usingnamespacestd;usingi64=longlon......
  • 回归预测|一种多输入多输出的粒子群优化支持向量机数据回归预测Matlab程序PSO-MSVR非f
    回归预测|一种多输入多输出的粒子群优化支持向量机数据回归预测Matlab程序PSO-MSVR非for循环实现原理上进行修改多输出文章目录前言回归预测|一种多输入多输出的粒子群优化支持向量机数据回归预测Matlab程序PSO-MSVR非for循环实现原理上进行修改多输出一、PSO-MSVR......
  • 达梦数据库有关hash及分组等操作相关优化
    最近在项目中调试存储过程碰到一些关于hash及分组相关的性能问题示例1:在调试过程中, 该sql执行很久后面报超出全局hashjoin空间的错误,重新调整HJ_BUF_GLOBAL_SIZE,执行一个小时也不出结果。INSERTINTOt_test(SELECTFundID,SeatNo,SUM(Balance),SUM(Available),SUM(In......
  • 优化if/else
    一、策略模式策略模式(StrategyPattern)是一种行为设计模式,它允许你定义一系列算法,把每个算法封装起来,并让它们可以互相替换。这种模式使得算法可以在不影响客户端的情况下发生变化。在策略模式中,有三个主要的角色:策略接口(Strategy):通常是一个接口,定义了一个算法家族的所有算法......
  • 【线段树合并/树上差分】[P4556 [Vani有约会] 雨天的尾巴 /【模板】线段树合并
    【线段树合并/树上差分】P4556[Vani有约会]雨天的尾巴/【模板】线段树合并思路对\(x,y,lca(u,v),fa_{lca(u,v)}\)四个点进行树上差分,然后用线段树合并动态权值线段树。#include<bits/stdc++.h>usingnamespacestd;usingi64=longlong;template<classNode>str......
  • 线段树合并模板
    template<classNode>structPersidentSegmentTree{#definelc(u)tr[u].l#definerc(u)tr[u].rconstintn;inttot=0;vector<Node>tr;vector<int>root;PersidentSegmentTree():n(0){}PersidentSegmentTree(in......
  • Linux 【关于内核参数详解和优化】
    Linux内核参数是操作系统中用于调整和优化系统性能和行为的关键设置。Linux内核参数可以通过以下几种方式进行查看和修改:/proc/sys目录:大多数内核参数都可以在/proc/sys目录下找到,使用sysctl命令查看和设置这些参数。sysctl.conf文件:此文件通常位于/etc目录中,可以在系统启动......