首页 > 其他分享 >线段树

线段树

时间:2023-12-08 20:11:41浏览次数:32  
标签:结点 old string int 线段 mid build

首先是建树

我们先构建整棵树的框架

 

struct node
{
    int l,r;
    string data;
}g[N*4];
//不一定非要构建结构体,看题目需求,如果不涉及左右范围的话就可以直接构造数组

 


//n表示的是树上每个结点的数值,比如说第一个结点为1,那莫第一个结点的左子树为2,右子树为3
//l(是字母l,不是数字1)和r 表示的是该结点所包含的范围 比如说结点1所包含的范围是1~8,表示结点1左子树所能到达的最左端是1,右子树所能到达的最右端是8
void build(int u , int l , int r)
{
    g[u].l = l , g[u].r = r;//记录当前结点所包含的范围
    if(l == r) return;//如果l=r,表示该结点时叶子节点,因为他的范围只有它本身
    int mid = (l + r) >> 1;//这里注意mid应该是包含在左子树上的
    build(2 * u , l , mid);//递归到左子树上
    build(2 * u + 1 , mid + 1 , r);//递归到右子树上
}

 

因为我们要清楚将结点赋值与对结点的值进行修改是一样的操作,都是有改变的性质,所以我们统一用一个函数来表示

 

//u  还是表示的是树上每个结点的数值
//old 表示的是你要对第几个结点进行修改
//neu 表示你要对old这个结点修改为neu
void re(int u , int old , int neu) { if(g[u].l == old && g[u].r == old) g[u].data = neu;//如果当前结点的左范围和右范围都等于old,表示当前这个结点是叶子结点,并且该叶子节点是old结点,那莫我们就把当前的值修改为neu else{ int mid = (g[u].l + g[u].r) >> 1;//计算当前结点范围的中间值
    //刚才我们说过,mid是在左子树内的 if(old <= mid) re(u * 2 , old , neu);//如果old小于等于mid,说明我们要求的结点在当前节点的左子树上;反之,在右子树上 else re(u * 2 + 1 , old , neu); g[u].data = max(g[2 * u].data , g[2 * u + 1].data);//通过左右子树的值来求出当前非叶子结点的值 } }

 

查询过程

int find(int u , int l , int r)//要注意你需要返回的值
{
    if (g[u].l >= l && g[u].r <= r) return g[u].data;   // 树中节点,已经被完全包含在[l, r]中了
    
    int mid = (g[u].l + g[u].r) >> 1;//计算当前结点范围的中间值
    //刚才我们说过,mid是在左子树内的
    int v=0; 
    //下面这两步是死步骤,唯一不同的是看你需要求的是最大最小值,还是和
   if (l <= mid) v = find(u << 1, l, r); if (r > mid) v = max(v, find(u << 1 | 1, l, r)); return v; }

推荐牛客上的两个线段树的题

代码查看 (nowcoder.com)

代码查看 (nowcoder.com)

 

//这是第一个链接的完整代码

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+9;
string s[N];
struct node
{
    int l,r;
    string data;
}g[N*4];
int n,m;
void build(int u , int l , int r)
{
    g[u].l = l , g[u].r = r;
    if(l == r) return;
    int mid = (l + r) >> 1;
    build(2 * u , l , mid);
    build(2 * u + 1 , mid + 1 , r);
}
string find(int u , int l , int r)
{
    if (g[u].l >= l && g[u].r <= r) return g[u].data;   // 树中节点,已经被完全包含在[l, r]中了
    
    int mid = (g[u].l + g[u].r) >> 1;
    string v = "";
    if (l <= mid) v = find(u << 1, l, r);
    if (r > mid) v = max(v, find(u << 1 | 1, l, r));
    
    return v;
}
void re(int u , int old , string neu)
{
    if(g[u].l == old && g[u].r == old) g[u].data = neu;
    else{
        int mid = (g[u].l + g[u].r) >> 1;
        if(old <= mid) re(u * 2 , old , neu);
        else re(u * 2 + 1 , old , neu);
        g[u].data = max(g[2 * u].data , g[2 * u + 1].data);
    }
}
void solve()
{
    cin>>n>>m;
    build(1,1,N);
    for(int i=1;i<=n;i++)
    {
        string x;
        cin>>x;
        re(1,i,x);
    }
    
    for(int i=1;i<=m;i++)
    {
        char c;
        cin>>c;
        if(c=='U')
        {
            int idx; string x;
            cin >> idx >> x;
            re(1 , idx , x);
            
        }
        else
        {
            int l , r;
            cin >> l >> r;
            string t = find(1 , l , r);
            if(t.size() <= 0)
                t += "null";
            cout << t << endl;
        }
    }
}
int main()
{
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);
    solve();
}

 

标签:结点,old,string,int,线段,mid,build
From: https://www.cnblogs.com/kkklllaa/p/17888940.html

相关文章

  • 【数据结构】线段树 (二) 学习笔记
    线段树(二)点击查看:线段树(一)学习笔记本文介绍权值线段树与动态开点线段树,(可能后面还会加线段树合并等等)。权值线段树线段树的动态开点线段树合并推荐题目&&参考资料&&拓展阅读《算法竞赛进阶指南》0x43线段树P3870 [TJOI2009]开关P1438 无聊的数列P1253 扶苏的问......
  • 李超线段树
    问题:洛谷P4097在平面直角坐标系维护两个操作:1.加入一条线段。2.求目前平面直角坐标系中截一条直线\(x=k\)中与线段交点\(y\)最大的是那一条线段。解决:李超线段树模板。首先建一个以\(x\)为区间的线段树。和普通线段树的主要区别是在对懒标记的处理上,这里是是没有单独的下......
  • 线段树优化建图
    问题:CF786B给定一个\(n\)个点,\(m\)次连边的有向图,有三种连边(均有边权)方式:1.\(u\tov\),一条\(u\)指向\(v\)的连边。2.\(u\to[l,r]\),\(u\)向在区间\([l,r]\)的点分别连一条边。3.\([l,r]\tov\),在区间\([l,r]\)的点向\(v\)分别连一条边。问从\(1\)点出发,到各个点的最短路。......
  • 像使用stl一样使用线段树 ——AtCoder Library(转载https://zhuanlan.zhihu.com/p/459
    地址:https://zhuanlan.zhihu.com/p/459579152 我这里翻译一下官方的文档。首先需要满足几个性质。(注意 ∗ 是个操作,不是单纯的一个乘号)1)操作满足结合律即 (a∗b)∗c=a∗(b∗c)2)操作需要有个幺元(基本元/单位元)a∗e=e∗a=a如果你有这个一个序列S,长度为N ,接下......
  • 【2024省选冲刺计划】数据结构相关-线段树进阶
    线段树进阶0x01李超线段树FZPJ4519[2021冬令营模拟]上古遗迹【题目背景】“沙……沙……沙……”独行者的脚步一次次被刻进沙漠中,干冷的风携沙尘在男子的四围穿过。“该死……这沙尘什么时候才能消停会儿……”男子止不住地咳嗽,随即停了下来,开始查看便携式投影设备上的信......
  • 树状数组和线段树
    树状数组:1.将某一个数加上k2.求出某区间每一个数的和#include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;lln,m,a[500000+10];lllowbit(llx){returnx&(-x);}voidadd(llx,llk){ while(x<=n){ a[x]+=k; x+=lowbit(x); }}llquery(llx){ ll......
  • 线段树优化建图
    CF786B题意:定义\((u,v,w)\)表示\(u\)向\(v\)连了边权为\(w\)的边。有三种连边操作\((u,v,w)\)\(\foralli\in[l,r],(u,i,w)\)\(\foralli\in[l,r],(i,u,w)\)求最短路。暴力加边是\(O(nm)\)的,考虑优化。可以把图建到线段树上,线段树每个结点向左右儿子连\(w......
  • 【刷题记录】20231124 线段树分治
    做题记录:注意到每次相当于\(0\)后面加\(1\),\(1\)后面加\(0\),因此每次可以合并01和10然后将问题规模减半。黑白染色,白格子=lcm+1,黑格子=prime相乘。发现横着竖着有六个质数,斜着只用四个质数。调整一下顺序即可。状压DP。考虑S作为前缀max时S与U-S的排列方案数。S每......
  • 交点 - 求两线段交点2
    效果 会用到的知识相交-两线段是否相交-yanghui01-博客园(cnblogs.com)线性代数-已知点求直线方程-yanghui01-博客园(cnblogs.com)交点-两直线交点-yanghui01-博客园(cnblogs.com) //两线段是否相交publicstaticboolIsTwoSegmentIntersect2(V......
  • 「线段树」笔记
    基础建树voidbuild(intp,intl,intr){ t[p]=(tree){l,r,0}; if(l==r) { t[p].sum=val[l]; return; } intmid=(l+r)>>1; build(lp,l,mid); build(rp,mid+1,r); pushup(p);}单点修改(和)voidupdate(intp,intx,intk){ if(t[......