首页 > 其他分享 >【刷题】【线段树】

【刷题】【线段树】

时间:2022-09-19 00:22:53浏览次数:100  
标签:rt int 线段 tr mid len laz 刷题

(1)Laz标记:

题目:区区区间

区区区间 (nowcoder.com)

题解摘自:区区区间 _牛客博客 (nowcoder.net)

  我们发现这个等差数列的等差为1。对于修改一段区间l-rl−r如果我们知道首项值,那么我们便可以在O(1)O(1)的时间复杂度计算出这段区间的大小。

  又可以知道,对于线段树每一个结点,代表一段区间,那么我们我们用lazy数组保存这一段区间的首项,那么我们便可以在O(1)的时间复杂度内算出这一段区间的值。

代码:

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

int n,m;
const int N=1e6+10;
int d[N];

int root,cnt;
struct node
{
    int lson,rson;
    ll sum; int len;
    int laz;            //这里的k表示首项 
}tr[N<<2];

void update(int rt)
{
    int ls = tr[rt].lson ,rs = tr[rt].rson ;
    tr[rt].sum = tr[ls].sum + tr[rs].sum ;
}

void build(int & rt,int l,int r)
{
    rt=++cnt;
    tr[rt].len = r-l+1;
    if(l==r)
    {
        tr[rt].sum = d[l];
        return ;
    }
    
    int mid=(l+r)>>1;
    build(tr[rt].lson ,l,mid);
    build(tr[rt].rson ,mid+1,r);
    update(rt);
}

ll get_sum(int rt,int laz,int len)
{
    return 1LL*(laz + laz+len-1)*len/2;
}

void push_down(int rt,int l,int mid)
{
    int ls = tr[rt].lson ,rs = tr[rt].rson ;
    int v=tr[rt].laz; tr[rt].laz = 0;
    tr[ls].laz = v , tr[rs].laz = v+mid-l+1 ;
    tr[ls].sum = get_sum(ls,tr[ls].laz ,tr[ls].len ) , tr[rs].sum = get_sum(rs,tr[rs].laz ,tr[rs].len ) ;
}

int ql,qr,qv;
void change(int rt,int l,int r) //给ql到qr区间上,加上qv 
{
    if(ql<=l && r<=qr )
    {
        int fst=qv+l-ql;
        tr[rt].laz = fst;
        tr[rt].sum = get_sum(rt,tr[rt].laz,tr[rt].len);
        return ;
    }
    
    int mid=(l+r)>>1;
    if(tr[rt].laz ) push_down(rt,l,mid);
    if(qr<=mid ) change(tr[rt].lson ,l,mid);
    else if(mid<ql ) change(tr[rt].rson ,mid+1,r);
    else 
        change(tr[rt].lson ,l,mid),
        change(tr[rt].rson ,mid+1,r);
    update(rt);
}

ll query(int rt,int l,int r)
{
    if(ql<=l && r<=qr )
        return tr[rt].sum;
    
    int mid=(l+r)>>1;
    if(tr[rt].laz ) push_down(rt,l,mid);
    if(qr<=mid ) return query(tr[rt].lson ,l,mid);
    else if(mid<ql ) return query(tr[rt].rson ,mid+1,r);
    else 
        return query(tr[rt].lson ,l,mid) + query(tr[rt].rson ,mid+1,r);
}

int main()
{
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n;i++)
        scanf("%d",&d[i]);
    build(root,1,n);
    
    int op,a,b,c;
    while(m--)
    {
        scanf("%d%d%d",&op,&a,&b);
        if(op==1)
        {
            scanf("%d",&qv);
            ql=a,qr=b;
            change(root,1,n);
        }
        else
        {
            ql=a,qr=b;
            printf("%lld\n",query(root,1,n));
        }
    }
    
    return 0;
} 
View Code

 

(2)

 

标签:rt,int,线段,tr,mid,len,laz,刷题
From: https://www.cnblogs.com/xwww666666/p/16706352.html

相关文章

  • 线段树
    给出一个数组每个数组的值代表一个集合相邻的两个集合不能重合问集合中的最大数是多少线段树维护这个区间的相邻数的最大值因为相邻的条件所以边界需要特判#include<......
  • dp线段树优化
    题目:PottedFlowerDescriptionThelittlecattakesoverthemanagementofanewpark.Thereisalargecircularstatueinthecenterofthepark,surroundedby......
  • 可持久化线段树
    现想现写的,没有借鉴别人的任何东西。可持久化线段树1考虑不会变得太多,每次该值操作只会改变一个位置的值,其它位置是可以继承的。如果用数组,那就是下标继承。如果把数组分......
  • 记刷题过程中发现的C++与C的差异
    前言上大学了,学c。标题嫖自@快乐永恒正题01#include<stdio.h>intmain(){longlonga,b;scanf("%lld%lld",&a,&b);printf("%lld%lld%lld%lld%l......
  • Slayers Come (区间覆盖种类数(dp+线段树)+ st表+二分,或者线段树) (2022杭电多校2)
    题目;给你一个长度为n的数组,每个位置上有一个野怪,野怪的攻击力和血量已知,你有m个技能,每个技能有三个值,一是可以击败的怪物,且怪物死后会攻击与它相邻的怪对于左边的怪伤害......
  • Static Query on Tree (述链剖分+线段树)(2022杭电多校)
    题意:给定一棵树,nn 个结点。根为 11,所有的结点只能走向其父亲结点。有 qq 次询问,每次询问给出 33 个结点集合 A,B,CA,B,C。问树上有多少点满足如下条件:该点可以......
  • DOS Card (线段树)(hud杭电多校)
    题目:对序列 a,回答 q 次询问:给定长度至少为 4 的区间 [L,R],在区间内选择 1对 (ai,aj)(L≤i<j≤R)可以获取分数 (ai+aj)(ai−aj) ,计算选择 2 对可以获取的最......
  • 【luogu CF633H】Fibonacci-ish II(莫队)(线段树)(矩阵乘法)
    Fibonacci-ishII题目链接:luoguCF633H题目大意给你一个序列,每次问你一个区间,把里面的数拿出来去重排序,第i个位置乘上斐波那契数列第i项之后所有数的和。思路这题......
  • 线段树
    #include<bits/stdc++.h>usingnamespacestd;typedeflonglongll;constintN=100001;llsum[N*4];lltag[N*4];inta[N];voidpushdown(intx,intl_len,......
  • CF446C(线段树+斐波那契)
    CF446C(线段树+斐波那契数列)CF链接洛谷链接题目大意:区间加斐波那契数列,区间求和分析:一眼鉴定为线段树难点在于如何打标记,合并和传递标记对于斐波那契数列有几个性......