线段树模板

我死辽为什么板子那么难调awsl

第一题:

 

注意空间要开4倍,写位运算的话左移右移不要打错啊;

#include<bits/stdc++.h>
using namespace std;
#define N 500010
const int inf = 0x3f3f3f3f;
template<typename T>inline void read(T &x)
{
    x=0;T f=1,ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch)) {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x*=f;
}
struct gg
{
    int l,r,dat;
}tre[N*4];
int a[N],n,m,x,y,ty; 
inline void build(int p,int l,int r)
{
    tre[p].l=l,tre[p].r=r;
    if(l==r) {tre[p].dat=a[l];return ;}
    int mid=(l+r)>>1;
        build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    tre[p].dat=max(tre[p<<1].dat,tre[p<<1|1].dat);
}
inline void change(int p,int x,int v)
{
    if(tre[p].l==tre[p].r) {tre[p].dat=v;return ;}
    int mid=(tre[p].l+tre[p].r)>>1;
    if(x<=mid) change(p<<1,x,v);
    else  change(p<<1|1,x,v);
    tre[p].dat=max(tre[p<<1].dat,tre[p<<1|1].dat);
}
inline int ask(int p,int l,int r)
{
    if(l<=tre[p].l&&r>=tre[p].r)  return tre[p].dat;
    int mid=(tre[p].l+tre[p].r)>>1;
    int val=-inf;
    if(l<=mid) val=max(val,ask(p<<1,l,r));
    if(r>mid)  val=max(val,ask(p<<1|1,l,r));
    return val;
}
int main()
{
    read(n);
    memset(a, 0, sizeof(a));
    build(1, 1, n);
    for(int i=1;i<=n;i++)
    {
        read(ty);read(x);read(y);
        if(ty==1)change(1,x,y);
        else
        {
            printf("%d\n",ask(1,x,y));
        }
    }
    return 0;
} 
View youyi

第二题:

先说一下延迟标记吧,在线段树的区间查询指令中,每当遇到被查询的区间[L,R]完全覆盖的节点时,,可以立即把该节点上储存的信息作为候选答案返回,他会被分为O(lodN)个小区间,不过,在区间修改时,每当遇到被查询的区间[L,R]完全覆盖的节点时,那么以该节点为根的整棵子树,所以复杂度都会升到O(N);

我们可以对于每个结点增加一个属性:int add;add记录的是此节点所代表的区间所有数被加的值

每一个节点新添加一个标记,记录这个节点是否进行了某种改动(这样的改动操作会影响其子节点),对于随意区间的改动,我们先依照区间查询的方式将其划分成线段树中的节点,然后改动这些节点的信息,并给这些节点标记上代表这样的改动操作的标记。在改动和查询的时候,假设我们到了一个节点p,而且决定考虑其子节点,那么我们就要看节点p是否被标记,若设有,就要依照标记改动其子节点的信息,而且给子节点都标上同样的标记,同一时候消掉节点p的标记。这样每条查询和修改都是O(logN)了;

注释在代码;

 

#include<bits/stdc++.h>
using namespace std;
#define l(x) tre[x].l
#define r(x) tre[x].r
#define sum(x) tre[x].sum
#define add(x) tre[x].add 
#define dat(x) tre[x].dat
template<typename T>inline void read(T &x)
{
    x=0;T f=1,ch=getchar();
    while(!isdigit(ch)) {if(ch=='-') f=-1;ch=getchar();}
    while(isdigit(ch))  {x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}
    x*=f;
}
struct gg
{
    int l,r,dat;
    long long sum,add;//sum是区间和,add是增量延迟标记; 
    
}tre[2000010];
int a[1000010],n,m,op,l,r,d;

inline void build(int p,int l,int r)
{
    l(p)=l;r(p)=r;
    if(l==r) {dat(p)=a[l];return ;}
    int mid=l+r>>1;
    build(p<<1,l,mid);
    build(p<<1|1,mid+1,r);
    dat(p)=max(dat(p<<1),dat(p<<1|1));
    sum(p)=sum(p<<1)+sum(p<<1|1); 
}
inline void spread(int p)
{
    if(add(p))//如果p点有标记
    {
        sum(p<<1)+=add(p)*((r(p<<1))-l(p<<1)+1);//更新左节点信息; 
        sum(p<<1|1)+=add(p)*(r(p<<1|1)-l(p<<1|1)+1);//更新右节点信息;
        add(p<<1)+=add(p);//给左节点左做延迟标记 
        add(p<<1|1)+=add(p); //给右节点做延迟标记 
        dat(p<<1)+=add(p);
        dat(p<<1|1)+=add(p);
        add(p)=0;//清除p的标记; 
    } 
}
inline void change(int p,int l,int r,int d)
{
    if(l<=l(p)&&r>=r(p))
    {
        sum(p)+=(long long)d*(r(p)-l(p)+1);
        add(p)+=d;
        dat(p)+=d;
        return ;
    }
    spread(p);
    int mid=(l(p)+r(p))>>1;
    if(l<=mid) change(p<<1,l,r,d);
    if(r>mid) change(p<<1|1,l,r,d);
    sum(p)=sum(p<<1)+sum(p<<1|1);
    dat(p)=max(dat(p<<1),dat(p<<1|1)); 
} 
inline long long ask(int p,int l,int r)
{
    if(l<=l(p)&&r>=r(p))    return dat(p);
    spread(p);
    int mid=(l(p)+r(p))>>1;
    long long val=-(1<<30);
    if(l<=mid) val=max(val,ask(p<<1,l,r));
    if(r>mid) val=max(val,ask(p<<1|1,l,r));
    return val; 
}
int main()
{
    read(m);
    build(1,1,m);
    for(int i=1;i<=m;i++)
    {
        read(op);
        if(op==1)
        {
            read(l);read(r);
            change(1,l,r,1);
        }
        else
        {
            read(l);read(r);
            printf("%d\n",ask(1,l,r));
        }
    }
    return 0;
}
View Code

 

posted @ 2019-03-28 09:42  Tyouchie  阅读(153)  评论(0编辑  收藏  举报