线段树练习两题

1.线段树练习1:

 输入:n
         (n个数)
k (k 行) 1 k p 将a[k]改为p 2 l r 区间查询
  1 /*
  2 一开始看错题目了,没有看到要求:“l<=j<=i<=r”的条件
  3 这是错误代码:
  4 */
  5 /*错误代码:
  6 */
  7 #include<iostream>
  8 using namespace std;
  9 #include<cstdio>
 10 #define N 10000
 11 #define mid ((l+r)>>1)
 12 #define lch (2*k)
 13 #define rch ((2*k)+1)
 14 struct Jg{
 15     int firs,secn;
 16 };
 17 struct Tree{
 18     int minn,maxx;
 19 }tree[N<<2];
 20 int n,k,sum[N];
 21 inline int read()
 22 {
 23     int ret=0,ff=1;
 24     char s=getchar();
 25     while(s<'0'||s>'9')
 26     {
 27         if(s=='-') ff=-1;
 28         s=getchar();
 29     }
 30     while(s>='0'&&s<='9')
 31     {
 32         ret=ret*10+s-'0';
 33         s=getchar();
 34     }
 35     return ret*ff;
 36 }
 37 void input()
 38 {
 39     n=read();
 40     for(int i=1;i<=n;++i)
 41       sum[i]=read();
 42 }
 43 void update(int k)
 44 {
 45     tree[k].maxx=max(tree[lch].maxx,tree[rch].maxx);
 46     tree[k].minn=min(tree[lch].minn,tree[rch].minn);
 47     return;
 48 }
 49 void build(int k,int l,int r)
 50 {
 51     if(l==r)
 52     {
 53         tree[k].minn=tree[k].maxx=sum[l];
 54         return;
 55     }
 56     build(lch,l,mid);
 57     build(rch,mid+1,r);
 58     update(k);
 59 }
 60 void change(int k,int l,int r,int pos,int z)
 61 {
 62     if(l==r)
 63     {
 64         tree[k].maxx=tree[k].minn=z;
 65         return ;
 66     }
 67     if(pos<=mid) change(lch,l,mid,pos,z);
 68     else change(rch,mid+1,r,pos,z);
 69     update(k);
 70 }
 71 Jg query(int k,int l,int r,int x,int y)
 72 {
 73     if(x<=l&&r<=y)
 74     {
 75         return Jg{tree[k].maxx,tree[k].minn};/*这里是必须要返回最大值和最小值的,因为可能都有用,不能只返回max-min,这样是不对的。*/
 76     }
 77     int maxxx=-1000000000,minnn=1000000000;
 78     Jg A={maxxx,minnn},B={maxxx,minnn};
 79     if(x<=mid)
 80       A=query(lch,l,mid,x,y);
 81     if(y>mid)
 82       B=query(rch,mid+1,r,x,y);
 83     return Jg{max(A.firs,B.firs),min(A.secn,B.secn)};
 84  } 
 85 int main()
 86 {
 87     input();
 88     build(1,1,n);
 89     k=read();
 90     int x,y,z;
 91     for(int i=1;i<=k;++i)
 92     {
 93         x=read();y=read();z=read();
 94         if(x==1)
 95         {
 96             change(1,1,n,y,z);
 97         }
 98         else {
 99             Jg P=query(1,1,n,y,z);
100             printf("%d
",P.firs-P.secn);
101         }
102     }
103     return 0;
104  }

解析:

  1 /*正确代码:值得注意的一点:就是每个区间初始的ans值必须是最小的,叶子节点上的ans不能是自身,这样是没有正确意义的。
  2 */
  3 #include<iostream>
  4 using namespace std;
  5 #include<cstdio>
  6 #define N 10000
  7 #define mid ((l+r)>>1)
  8 #define lch (2*k)
  9 #define rch ((2*k)+1)
 10 struct Jg{
 11     int firs,secn,thir;
 12 };
 13 struct Tree{
 14     int minn,maxx,ans;
 15 }tree[N<<2];
 16 int n,k,sum[N];
 17 inline int read()
 18 {
 19     int ret=0,ff=1;
 20     char s=getchar();
 21     while(s<'0'||s>'9')
 22     {
 23         if(s=='-') ff=-1;
 24         s=getchar();
 25     }
 26     while(s>='0'&&s<='9')
 27     {
 28         ret=ret*10+s-'0';
 29         s=getchar();
 30     }
 31     return ret*ff;
 32 }
 33 void input()
 34 {
 35     n=read();
 36     for(int i=1;i<=n;++i)
 37       sum[i]=read();
 38 }
 39 void update(int k)
 40 {
 41     tree[k].maxx=max(tree[lch].maxx,tree[rch].maxx);
 42     tree[k].minn=min(tree[lch].minn,tree[rch].minn);
 43     tree[k].ans=max(max(tree[k].ans,tree[rch].maxx-tree[k].minn),max(tree[lch].ans,tree[rch].ans));
 44     return;
 45 }
 46 void build(int k,int l,int r)
 47 {
 48     if(l==r)
 49     {
 50         tree[k].minn=tree[k].maxx=sum[l];
 51         tree[k].ans=-1000000000;
 52         return;
 53     }
 54     build(lch,l,mid);
 55     build(rch,mid+1,r);
 56     update(k);
 57 }
 58 void change(int k,int l,int r,int pos,int z)
 59 {
 60     if(l==r)
 61     {
 62         tree[k].maxx=tree[k].minn=z;
 63         return;
 64     }
 65     if(pos<=mid) change(lch,l,mid,pos,z);
 66     else change(rch,mid+1,r,pos,z);
 67     update(k);
 68 }
 69 Jg query(int k,int l,int r,int x,int y)
 70 {
 71     if(x<=l&&r<=y)
 72     {
 73         return Jg{tree[k].maxx,tree[k].minn,tree[k].ans};
 74     }
 75     int maxxx=-1000000000,minnn=1000000000;
 76     Jg A={maxxx,minnn,maxxx},B={maxxx,minnn,maxxx};
 77     if(x<=mid)
 78       A=query(lch,l,mid,x,y);
 79     if(y>mid)
 80       B=query(rch,mid+1,r,x,y);
 81     return Jg{max(A.firs,B.firs),min(A.secn,B.secn),max(B.firs-A.secn,max(A.thir,B.thir))};
 82  } 
 83 int main()
 84 {
 85     input();
 86     build(1,1,n);
 87     k=read();
 88     int x,y,z;
 89     for(int i=1;i<=k;++i)
 90     {
 91         x=read();y=read();z=read();
 92         if(x==1)
 93         {
 94             change(1,1,n,y,z);
 95         }
 96         else {
 97             Jg P=query(1,1,n,y,z);
 98             printf("%d
",P.thir);
 99         }
100     }
101     return 0;
102  }

 2.线段树练习2:布尔数组

输入:

1  输入:n
2          (n个数)
3       k
4          (k  行) 1  k p 将a[k]改为p
5                   2  l  r 区间查询

 解析:

 代码:

  1 /*
  2 这道题目的关键就是这个递推关系
  3 */
  4 #define N 100000
  5 #include<iostream>
  6 #include<cstdio>
  7 #define lch (k<<1)
  8 #define rch ((k<<1)+1)
  9 #define mid ((l+r)>>1)
 10 using namespace std;
 11 struct Jg{
 12     int llen,rlen,ans;
 13 };
 14 struct Tree{
 15     int llen,rlen,ans;
 16 }segt[N<<2];
 17 int n,k,sum[N];
 18 void input()
 19 {
 20     scanf("%d",&n);
 21     for(int i=1;i<=n;++i)
 22        scanf("%d",&sum[i]);
 23 }
 24 void update(int k,int l,int r)
 25 {
 26     if(sum[mid]!=sum[mid+1]&&segt[lch].llen==mid+1-l)
 27       segt[k].llen=mid+1-l+segt[rch].llen;
 28     else segt[k].llen=segt[lch].llen;
 29     if(sum[mid]!=sum[mid+1]&&segt[rch].rlen==r-mid)
 30       segt[k].rlen=r-mid+segt[lch].rlen;
 31     else segt[k].rlen=segt[rch].rlen;
 32     segt[k].ans=max(segt[lch].ans,segt[rch].ans);
 33     if(sum[mid]!=sum[mid+1])
 34        segt[k].ans=max(segt[k].ans,segt[rch].llen+segt[lch].rlen);
 35     
 36 }
 37 void build_segt(int k,int l,int r)
 38 {
 39     if(l==r)
 40     {
 41         segt[k].ans=segt[k].llen=segt[k].rlen=1;
 42         return;
 43     }
 44     build_segt(lch,l,mid);
 45     build_segt(rch,mid+1,r);
 46     update(k,l,r);
 47 }
 48 void change(int k,int l,int r,int pos,int z)
 49 {
 50     if(l==r)
 51     {
 52         sum[pos]=z;
 53         return;
 54     }
 55     if(pos<=mid)
 56       change(lch,l,mid,pos,z);
 57     else change(rch,mid+1,r,pos,z);
 58     update(k,l,r);
 59 }
 60 Jg query(int k,int l,int r,int x,int y)
 61 {
 62     if(x<=l&&r<=y)
 63     {
 64         return Jg{segt[k].llen,segt[k].rlen,segt[k].ans};
 65     }
 66     if(x>mid)
 67       return query(rch,mid+1,r,x,y);
 68     if(y<=mid) return query(lch,l,mid,x,y);
 69     Jg B=query(rch,mid+1,r,x,y);
 70     Jg A=query(lch,l,mid,x,y);
 71     int llen,rlen,ans;/*注意这里的A,B区间不一定是规则的区间,有可能是几个区间拼凑在一起,但是一定有A与B相邻*/
 72     /*这道题目的关键就是这个递推关系*/
 73     if(sum[mid]!=sum[mid+1]&&A.llen==mid+1-x)
 74       llen=mid+1-l+B.llen;
 75     else llen=A.llen;
 76     if(sum[mid]!=sum[mid+1]&&B.rlen==r-mid)
 77       rlen=r-mid+A.rlen;
 78     else rlen=B.rlen;
 79     ans=max(A.ans,B.ans);
 80     if(sum[mid]!=sum[mid+1])
 81        ans=max(ans,B.llen+A.rlen);
 82     return Jg{llen,rlen,ans};
 83 }
 84 int main()
 85 {
 86     input();
 87     build_segt(1,1,n);
 88     scanf("%d",&k);
 89     int x,y,z;
 90     for(int i=1;i<=n;++i)
 91     {
 92         scanf("%d%d%d",&x,&y,&z);
 93         if(x==1)
 94         {
 95             change(1,1,n,y,z);
 96         }
 97         else {
 98             Jg P=query(1,1,n,y,z);
 99             printf("%d
",P.ans);
100         }
101     }
102     return 0;
103 }
原文地址:https://www.cnblogs.com/c1299401227/p/5800870.html