ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

沙雕关于线段树的一点总结(滑稽)

2019-08-13 09:55:59  阅读:245  来源: 互联网

标签:ch return int 线段 滑稽 mid long && 沙雕


这段时间(好吧其实只有昨天)写了一点线段树,虽然我是个蒟蒻啥都不会只会傻敷敷的网上去复制别人的代码但是经过我长时间的观察还是有一点点收获的滑稽。

先变成我头部的颜色

一般呢,在写线段树的时候 k,l,r 即序号,左右边界是分不开的,其他参数看题目不同而自行决腚。

如果你这三个不凑齐还能AC我就把电脑屏幕吃了

好吧进入正题

本人学习用的是信息学奥赛一本通,感觉还行,但是没有漫画好看

一本通上常用的写法有以下几种(在几种不同的情境下) 建树过程没什么好说的

1.求max或者min(此处以min为例)

一.询问

int query(int k,int l,int r,int x,int y)
{
    if(y<l||x>r) return 233333333;
    if(x<=l&&r<=y) return Min[k];
    int mid=l+r>>1;
    return min(query(k<<1,l,mid,x,y),query(k<<1|1,mid+1,r,x,y));
}

 

 

 

二.修改(单点修改)

void change(int k,int l,int r,int x,int v)
{
    if(r<x||l>x) return ;
    if(l==r&&l==x)
    {
        Min[k]=v;
        return ;
    }
    int mid=l+r>>1;
    change(k<<1,l,mid,x,v);
    change(k<<1|1,mid+1,r,x,v);
    Min[k]=min(Min[k<<1],Min[k<<1|1]);
}

 

 

 

敲得比较快不过问题不大反正没人看(滑稽)

好吧我比较懒接下来上几道ybtOJ的题目再来体会一下

忽略这个书签

1547 区间和

#include<bits/stdc++.h>
using namespace std;
const int N=100001;
int n,m;
long long sum[N*4];
 int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void change(int k,int l,int r,int p,int v)
{
    if(r<p||l>p) return ;
    if(l==r&&l==p) 
    {
        sum[k]+=v;
        return ;
    } 
    int mid=l+r>>1;
    change(k*2,l,mid,p,v);
    change(k*2+1,mid+1,r,p,v);
    sum[k]=sum[k*2]+sum[k*2+1];
}
long long query(int k,int l,int r,int x,int y)
{
    if(y<l||x>r) return 0;
    if(l>=x&&r<=y) return sum[k];
    int mid=l+r>>1;
    long long ans=0;
    ans=query(k*2,l,mid,x,y);
    ans+=query(k*2+1,mid+1,r,x,y);
    return ans;
}
int main()
{
    n=read();m=read();
    int k,l,r;
    for(int i=1;i<=m;i++)
    {
        k=read();l=read();r=read();
        if(k==0)
        change(1,1,n,l,r);
        else printf("%lld\n",query(1,1,n,l,r));
    }
    return 0;
}

 

以及1548:【例 2】A Simple Problem with Integers

#include<bits/stdc++.h>
using namespace std;
const int N=1e6+1;
long long sum[N*4],add[N*4];
int a[N],n,q;
inline int read()
{
    int x=0,f=1;
    char ch=getchar();
    while(ch<'0'||ch>'9')
    {
        if(ch=='-') f=-1;
        ch=getchar();
    }
    while(ch>='0'&&ch<='9')
    {
        x=x*10+ch-'0';
        ch=getchar();
    }
    return x*f;
}
void build(int k,int l,int r)
{
    if(l==r)
    {
        sum[k]=a[l];
        return ;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}
void Add(int k,int l,int r,int v)
{
    add[k]+=v;
    sum[k]+=(long long)v*(r-l+1);
}
void pushdown(int k,int l,int r,int mid)
{
    if(add[k]==0) return ;
    Add(k<<1,l,mid,add[k]);
    Add(k<<1|1,mid+1,r,add[k]);
    add[k]=0;
}
long long query(int k,int l,int r,int x,int y)
{
    if(l>=x&&r<=y) return sum[k];
    int mid=l+r>>1;
    long long ans=0;
    pushdown(k,l,r,mid);
    if(x<=mid) ans+=query(k<<1,l,mid,x,y);
    if(y>mid) ans+=query(k<<1|1,mid+1,r,x,y);
    return ans;
}
void change(int k,int l,int r,int x,int y,int v)
{
    if(l>=x&&r<=y) return Add(k,l,r,v);
    int mid=l+r>>1;
    pushdown(k,l,r,mid);
    if(x<=mid) change(k<<1,l,mid,x,y,v);
    if(y>mid) change(k<<1|1,mid+1,r,x,y,v);
    sum[k]=sum[k<<1]+sum[k<<1|1];
}
int main()
{
    n=read();q=read();
    for(int i=1;i<=n;i++)
    a[i]=read();
    build(1,1,n);
    int way,L,R,v;
    for(int i=1;i<=q;i++)
    {
        way=read();
        if(way==1) 
        {
            L=read();R=read();v=read();
            change(1,1,n,L,R,v);
        }
        else {
            L=read();
            R=read();printf("%lld\n",query(1,1,n,L,R));
        }
    }
    return 0;
}

由此可见(以上都是例题)ybt上的线段树代码不会刻意去压缩寻找的区间(即减少了过多的if语句判断条件)

这样可以降低编程时的复杂度而且对O的影响也不大但是可能可读性就会差一些

而且部分题目如果使用这种方法会很棘手

#include<bits/stdc++.h>
#define ll long long
using namespace std;
const int N=1e5+1;
int n,m;
struct Node{
    ll sum;
    bool flag;
}t[N<<2];
int a[N];
inline void build(int k,int l,int r)
{
    if(l==r) 
    {
        t[k].sum=(ll)a[l];
        if(t[k].sum==0||t[k].sum==1) t[k].flag=1;
        return ;
    }
    int mid=l+r>>1;
    build(k<<1,l,mid);
    build(k<<1|1,mid+1,r);
    t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
    t[k].flag=t[k<<1].flag&t[k<<1|1].flag;
}
inline long long query(int k,int l,int r,int x,int y)
{
    if(l>y||r<x) return 0;
    if(l>=x&&r<=y) return t[k].sum;
    int mid=l+r>>1;
    long long ans=0;
    if(x<=mid) ans+=query(k<<1,l,mid,x,y);
    if(y>mid) ans+=query(k<<1|1,mid+1,r,x,y);
    return ans;
}
inline void change(int k,int l,int r,int x,int y)
{
    if(t[k].flag) return ;
    if(l==r)
    {
        t[k].sum=(ll)sqrt(t[k].sum);
        if(t[k].sum==1||t[k].sum==0) t[k].flag=1;
        return ;
    }
    int mid=l+r>>1;
    if(x>mid) change(k<<1|1,mid+1,r,x,y);
    else if(y<=mid) change(k<<1,l,mid,x,y);
    else {
        change(k<<1,l,mid,x,y);
        change(k<<1|1,mid+1,r,x,y);
    }
    t[k].sum=t[k<<1].sum+t[k<<1|1].sum;
    t[k].flag=t[k<<1].flag&t[k<<1|1].flag;
}
int main()
{
    scanf("%d",&n);
    for(int i=1;i<=n;i++)
    scanf("%d",&a[i]);
    build(1,1,n);
    scanf("%d",&m);
    int a,b,c;
    for(int i=1;i<=m;i++)
    {
        scanf("%d%d%d",&a,&b,&c);
        if(a==1) printf("%lld\n",query(1,1,n,b,c));
        else change(1,1,n,b,c);
    }
    return 0;
}

这道题目是BZOJ3211 花神游历各国

这道题在修改过程中如果加上if语句判定来压缩寻找的区间就会方便很多

 

 

 

 

 

 

 

 

扯完了

 

 

 

标签:ch,return,int,线段,滑稽,mid,long,&&,沙雕
来源: https://www.cnblogs.com/smartljy/p/11344004.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有