• 线段树专题(持续更新中...)


    单点更新:最最基础的线段树,只更新叶子节点,然后把信息用PushUP(int r)这个函数更新上来

    • hdu1166 敌兵布阵

    • 线段树功能:update:单点增减 query:区间求和

    •   1 #include <iostream>
        2 #include <cstdio>
        3 #include <cstring>
        4 using namespace std;
        5 
        6 #define LL(x) (x<<1)
        7 #define RR(x) (x<<1|1)
        8 #define MID(a,b) (a+((b-a)>>1))
        9 const int N=50005;
       10 
       11 struct node
       12 {
       13     int lft,rht;
       14     int sum;
       15     int mid()
       16     {
       17         return MID(lft,rht);
       18     }
       19 };
       20 
       21 int y[N],n;
       22 
       23 struct Segtree
       24 {
       25     node tree[N*4];
       26     void build(int lft,int rht,int rt)
       27     {
       28         tree[rt].lft=lft;
       29         tree[rt].rht=rht;
       30         tree[rt].sum=0;
       31         if(lft==rht) 
       32             tree[rt].sum=y[lft];
       33         else
       34         {
       35             int mid=tree[rt].mid();
       36             build(lft,mid,LL(rt));
       37             build(mid+1,rht,RR(rt));
       38             tree[rt].sum=tree[LL(rt)].sum+tree[RR(rt)].sum;
       39         }
       40     }
       41     void updata(int pos,int rt,int valu)
       42     {
       43         if(tree[rt].lft==tree[rt].rht) 
       44             tree[rt].sum+=valu;
       45         else
       46         {
       47             int mid=tree[rt].mid();
       48             if(pos<=mid) 
       49                 updata(pos,LL(rt),valu);
       50             else 
       51                 updata(pos,RR(rt),valu);
       52             tree[rt].sum=tree[LL(rt)].sum+tree[RR(rt)].sum;
       53         }
       54     }
       55     int query(int st,int ed,int rt)
       56     {
       57         int lft=tree[rt].lft,rht=tree[rt].rht;
       58         if(st<=lft&&rht<=ed) 
       59             return tree[rt].sum;
       60         else
       61         {
       62             int mid=tree[rt].mid();
       63             int sum1=0,sum2=0;
       64             if(st<=mid) 
       65                 sum1=query(st,ed,LL(rt));
       66             if(ed>mid) 
       67                 sum2=query(st,ed,RR(rt));
       68             return sum1+sum2;
       69         }
       70     }
       71 }seg;
       72 int main()
       73 {
       74     int t,t_cnt=0;
       75     scanf("%d",&t);
       76     while(t--)
       77     {
       78         int a,b;
       79         char str[10];
       80         scanf("%d",&n);
       81         for(int i=1; i<=n; i++) 
       82             scanf("%d",&y[i]);
       83         seg.build(1,n,1);
       84         printf("Case %d:
      ",++t_cnt);
       85         while(1)
       86         {
       87             scanf("%s",str);
       88             if(strcmp(str,"End")==0) 
       89                 break;
       90             scanf("%d%d",&a,&b);
       91             if(strcmp(str,"Add")==0) 
       92                 seg.updata(a,1,b);
       93             else if(strcmp(str,"Sub")==0) 
       94                 seg.updata(a,1,-b);
       95             else 
       96                 printf("%d
      ",seg.query(a,b,1));
       97         }
       98     }
       99     return 0;
      100 }
      View Code

     hdu1754 I Hate It
      线段树功能:update:单点替换 query:区间最值,只要在上题代码的基础上稍加修改就好了,节点存储的是区间最大值

      

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 #define LL(x) (x<<1)
     7 #define RR(x) (x<<1|1)
     8 #define MID(a,b) (a+((b-a)>>1))
     9 const int N=200005;
    10 #define INF (1<<30)
    11 struct node
    12 {
    13     int lft,rht;
    14     int sum;
    15     int mid()
    16     {
    17         return MID(lft,rht);
    18     }
    19 };
    20 struct Segtree
    21 {
    22     node tree[N*4];
    23     void build(int lft,int rht,int rt)
    24     {
    25         tree[rt].lft=lft;
    26         tree[rt].rht=rht;
    27         tree[rt].sum=-INF;
    28         if(lft==rht)
    29             scanf("%d",&tree[rt].sum);
    30         else
    31         {
    32             int mid=tree[rt].mid();
    33             build(lft,mid,LL(rt));
    34             build(mid+1,rht,RR(rt));
    35             tree[rt].sum=max(tree[LL(rt)].sum,tree[RR(rt)].sum);
    36         }
    37     }
    38     void updata(int pos,int rt,int valu)
    39     {
    40         int lft=tree[rt].lft,rht=tree[rt].rht;
    41         if(tree[rt].lft==tree[rt].rht)
    42             tree[rt].sum=valu;
    43         else
    44         {
    45             int mid=tree[rt].mid();
    46             if(pos<=mid)
    47                 updata(pos,LL(rt),valu);
    48             else
    49                 updata(pos,RR(rt),valu);
    50             tree[rt].sum=max(tree[LL(rt)].sum,tree[RR(rt)].sum);
    51         }
    52     }
    53     int query(int st,int ed,int rt)
    54     {
    55         int lft=tree[rt].lft,rht=tree[rt].rht;
    56         if(st<=lft&&rht<=ed)
    57             return tree[rt].sum;
    58         else
    59         {
    60             int mid=tree[rt].mid();
    61             int sum1=-INF,sum2=-INF;
    62             if(st<=mid)
    63                 sum1=query(st,ed,LL(rt));
    64             if(ed>mid)
    65                 sum2=query(st,ed,RR(rt));
    66             return max(sum1,sum2);
    67         }
    68     }
    69 } seg;
    70 int main()
    71 {
    72     int n,m;
    73     while(scanf("%d%d",&n,&m)!=EOF)
    74     {
    75         int a,b;
    76         char str[10];
    77         seg.build(1,n,1);
    78         for(int i=0; i<m; i++)
    79         {
    80             scanf("%s",str);
    81             scanf("%d%d",&a,&b);
    82             if(str[0]=='Q')
    83                 printf("%d
    ",seg.query(a,b,1));
    84             else
    85                 seg.updata(a,1,b);
    86         }
    87     }
    88     return 0;
    89 }
    View Code

      

    hdu1394 Minimum Inversion Number
      题意:求改变后的最小逆序数
      思路:用O(nlogn)复杂度求出最初逆序数后,就可以用O(1)的复杂度分别递推出其他解
      线段树功能:update:单点增减 query:区间求和

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 #define LL(x) (x<<1)
     7 #define RR(x) (x<<1|1)
     8 #define MID(a,b) (a+((b-a)>>1))
     9 const int N=5005;
    10 #define INF (1<<30)
    11 struct node
    12 {
    13     int lft,rht;
    14     int sum;
    15     int mid()
    16     {
    17         return MID(lft,rht);
    18     }
    19 };
    20 struct Segtree
    21 {
    22     node tree[N*4];
    23     void build(int lft,int rht,int rt)
    24     {
    25         tree[rt].lft=lft;
    26         tree[rt].rht=rht;
    27         tree[rt].sum=0;
    28         if(lft!=rht)
    29         {
    30             int mid=tree[rt].mid();
    31             build(lft,mid,LL(rt));
    32             build(mid+1,rht,RR(rt));
    33         }
    34     }
    35     void updata(int pos,int rt)
    36     {
    37         int lft=tree[rt].lft,rht=tree[rt].rht;
    38         if(lft==rht)
    39             tree[rt].sum++;
    40         else
    41         {
    42             int mid=tree[rt].mid();
    43             if(pos<=mid)
    44                 updata(pos,LL(rt));
    45             else
    46                 updata(pos,RR(rt));
    47             tree[rt].sum=tree[LL(rt)].sum+tree[RR(rt)].sum;
    48         }
    49     }
    50     int query(int st,int ed,int rt)
    51     {
    52         int lft=tree[rt].lft,rht=tree[rt].rht;
    53         if(st<=lft&&rht<=ed)
    54             return tree[rt].sum;
    55         else
    56         {
    57             int mid=tree[rt].mid();
    58             int sum1=0,sum2=0;
    59             if(st<=mid)
    60                 sum1=query(st,ed,LL(rt));
    61             if(ed>mid)
    62                 sum2=query(st,ed,RR(rt));
    63             return sum1+sum2;
    64         }
    65     }
    66 } seg;
    67 int main()
    68 {
    69     int n;
    70     int sum;
    71     while(scanf("%d",&n)!=EOF)
    72     {
    73         sum=0;
    74         int a[5001];
    75         seg.build(0,n-1,1);
    76         for(int i=1; i<=n; i++)
    77         {
    78             scanf("%d",&a[i]);
    79             seg.updata(a[i],1);
    80             if(a[i]!=n-1)
    81                 sum+=seg.query(a[i]+1,n-1,1);
    82         }
    83         int minm=sum;
    84         for(int i=1;i<=n;i++)
    85         {
    86             sum-=a[i];
    87             sum+=n-a[i]-1;
    88             minm=min(minm,sum);
    89         }
    90         printf("%d
    ",minm);
    91     }
    92     return 0;
    93 }
    View Code

    hdu2795 Billboard
      题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子
      思路:因为最多只有二十万张海报,所以板的最大的长度不会超过二十万,但是要小心,如果板的长度小于h,我们还要用h来建树。起初在查询的时候并不直接去更新它,而是查询找出它的更新位置的后,再写个updata函数去更新,但是我们可以在查询到它的位置的时候,同时去更新当前点的剩余长度,然后回溯更新所有祖先区间。返回它的查询位置的时候,因为左儿子找到的位置是pos1,右儿子找到的位置是pos2,两者都赋初值为0,又因为每次查询只找出一个位置,也就是说pos1和pos2中只有一个被改变,另一个仍保持0,所以返回pos1+pos2是正确的。

      线段树功能:query:区间求最大值的位子

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 #define LL(x) (x<<1)
     7 #define RR(x) (x<<1|1)
     8 #define MID(a,b) (a+((b-a)>>1))
     9 const int N=200005;
    10 #define INF (1<<30)
    11 int h,w,n;
    12 struct node
    13 {
    14     int lft,rht;
    15     int sum;
    16     int mid()
    17     {
    18         return MID(lft,rht);
    19     }
    20 };
    21 struct Segtree
    22 {
    23     node tree[N*4];
    24     void build(int lft,int rht,int rt)
    25     {
    26         tree[rt].lft=lft;
    27         tree[rt].rht=rht;
    28         tree[rt].sum=w;
    29         if(lft!=rht)
    30         {
    31             int mid=tree[rt].mid();
    32             build(lft,mid,LL(rt));
    33             build(mid+1,rht,RR(rt));
    34         }
    35     }
    36     int updata(int value,int rt)
    37     {
    38         int pos;
    39         int lft=tree[rt].lft,rht=tree[rt].rht;
    40         if(lft==rht)
    41         {
    42             tree[rt].sum-=value;
    43             return lft;
    44         }
    45         else
    46         {
    47             if(tree[LL(rt)].sum>=value)
    48                 pos=updata(value,LL(rt));
    49             else
    50                 pos=updata(value,RR(rt));
    51             tree[rt].sum=max(tree[LL(rt)].sum,tree[RR(rt)].sum);
    52             return pos;
    53         }
    54     }
    55     /*int query(int st,int ed,int rt)
    56     {
    57         int lft=tree[rt].lft,rht=tree[rt].rht;
    58         if(st<=lft&&rht<=ed)
    59             return tree[rt].sum;
    60         else
    61         {
    62             int mid=tree[rt].mid();
    63             int sum1=0,sum2=0;
    64             if(st<=mid)
    65                 sum1=query(st,ed,LL(rt));
    66             if(ed>mid)
    67                 sum2=query(st,ed,RR(rt));
    68             return sum1+sum2;
    69         }
    70     }*/
    71 } seg;
    72 int main()
    73 {
    74     int p;
    75     while(scanf("%d%d%d",&h,&w,&n)!=EOF)
    76     {
    77         h=min(h,n);
    78         seg.build(1,h,1);
    79         for(int i=0; i<n; i++)
    80         {
    81             scanf("%d",&p);
    82             if(seg.tree[1].sum<p)
    83                 puts("-1");
    84             else
    85                 printf("%d
    ",seg.updata(p,1));
    86         }
    87     }
    88     return 0;
    89 }
    View Code

     hdu4521 小明系列问题——小明序列

        题意:有多组测试数据,每组数据的n和d表示,有n个数,求间距大于d的最长上升序列。

      思路:线段树中叶子结点表示值为i的并且以其结束的最长上升序列是多少。每次转移的时候,查询比当前值小的最大值就可以了。

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 using namespace std;
     5 
     6 #define LL(x) (x<<1)
     7 #define RR(x) (x<<1|1)
     8 #define MID(a,b) (a+((b-a)>>1))
     9 const int N=1e5+5;
    10 #define INF (1<<30)
    11 int a[N],n;
    12 int imx[N];//记录最大区间长度
    13 struct node
    14 {
    15     int lft,rht;
    16     int sum;
    17     int mid()
    18     {
    19         return MID(lft,rht);
    20     }
    21 };
    22 struct Segtree
    23 {
    24     node tree[N*4];
    25     void build(int lft,int rht,int rt)
    26     {
    27         tree[rt].lft=lft;
    28         tree[rt].rht=rht;
    29         tree[rt].sum=0;
    30         if(lft!=rht)
    31         {
    32             int mid=tree[rt].mid();
    33             build(lft,mid,LL(rt));
    34             build(mid+1,rht,RR(rt));
    35         }
    36     }
    37     void updata(int pos,int rt,int value)
    38     {
    39         int lft=tree[rt].lft,rht=tree[rt].rht;
    40         if(lft==rht)
    41         {
    42             tree[rt].sum=max(tree[rt].sum,value);
    43         }
    44         else
    45         {
    46             int mid=tree[rt].mid();
    47             if(pos<=mid)
    48                 updata(pos,LL(rt),value);
    49             else
    50                 updata(pos,RR(rt),value);
    51             tree[rt].sum=max(tree[LL(rt)].sum,tree[RR(rt)].sum);
    52         }
    53     }
    54     int query(int st,int ed,int rt)
    55     {
    56         int lft=tree[rt].lft,rht=tree[rt].rht;
    57         if(st<=lft&&rht<=ed)
    58             return tree[rt].sum;
    59         else
    60         {
    61             int mid=tree[rt].mid();
    62             int sum1=0,sum2=0;
    63             if(st<=mid)
    64                 sum1=query(st,ed,LL(rt));
    65             if(ed>mid)
    66                 sum2=query(st,ed,RR(rt));
    67             return max(sum1,sum2);
    68         }
    69     }
    70 } seg;
    71 int main()
    72 {
    73     int n,d;
    74     while(scanf("%d%d",&n,&d)!=EOF)
    75     {
    76         int maxm=0;
    77         int ans=0;
    78         for(int i=0;i<n;i++)
    79         {
    80             scanf("%d",&a[i]);
    81             maxm=max(maxm,a[i]);
    82             imx[i]=0;
    83         }
    84         seg.build(0,maxm,1);
    85         for(int i=0;i<n;i++)
    86         {
    87             if(i-d-1>=0)//间隔大于d
    88                 seg.updata(a[i-d-1],1,imx[i-d-1]);
    89             if(a[i]>0)
    90                 imx[i]=seg.query(0,a[i]-1,1)+1;//每次转移的时候,查询比当前值小的最大值就可以了。
    91             else
    92                 imx[i]=1;
    93             ans=max(ans,imx[i]);
    94         }
    95         printf("%d
    ",ans);
    96     }
    97     return 0;
    98 }
    View Code

    最近做多校做到一道线段树,刚开始不会做,看了题解才会的,弱!

    hdu5316 magician

      题意:给定n个数,m次操作,操作有两种
        (1)0 a b:输出区间[a,b]中美丽序列的最大和,区间[a,b]的美丽序列:[a,b]的子序列,且相邻元素的下标奇偶性不同
        (2)1 a b:将下标为a的值改为b

     思路:

      最大和要求子序列的相邻元素下标奇偶性不同,即下标奇偶交替即可
      则共有四种情况:子序列的开始下标和结尾下标为
      奇奇(jj),奇偶(jo),偶偶(oo),偶奇(oj)
      jj=jo+jj,jj=jj+oj,jo=jo+jo,jo=jj+oo
      oo=oo+jo,oo=oj+oo,oj=oo+oj,oj=oj+oj
      根据左右孩子推父结点时需要区间合并:(合并左右孩子)
      父结点的jj为 max(lson.jj,rson.jj,lson.jo+rson.jj,lson.jj+rson.oj)
      同样其他三种情况类推
      查询时要注意同样是区间合并(合并ans和包含要查询的子区间的结点),并不是单纯的取最大值
      最后的最大和为 max(ans.jj,ans.jo,ans.oj,ans.oo);
      因为题中存在负数,题中涉及到求最大值,相关的初始化要初始为负很大的数

    参考代码:

      1 #include<stdio.h>
      2 #include<algorithm>
      3 #include<string.h>
      4 #define inf 0xffffffffffff
      5 using namespace std;
      6 #define LL(x) (x<<1)
      7 #define RR(x) (x<<1|1)
      8 #define MID(a,b) (a+((b-a)>>1))
      9 typedef long long LL;
     10 const int N=100001;
     11 int n,m;
     12 LL a[N+10];
     13 struct node
     14 {
     15     LL jj,jo,oj,oo;
     16 } tt;
     17 struct Segtree
     18 {
     19     node tree[N*4];
     20     void pushup(node& t,node lson,node rson)
     21     {
     22         //更新jo
     23         t.jo=max(lson.jo,rson.jo);
     24         t.jo=max(t.jo,lson.jo+rson.jo);
     25         t.jo=max(t.jo,lson.jj+rson.oo);
     26         //更新jj
     27         t.jj=max(lson.jj,rson.jj);
     28         t.jj=max(t.jj,lson.jo+rson.jj);
     29         t.jj=max(t.jj,lson.jj+rson.oj);
     30         //更新oo
     31         t.oo=max(lson.oo,rson.oo);
     32         t.oo=max(t.oo,lson.oo+rson.jo);
     33         t.oo=max(t.oo,lson.oj+rson.oo);
     34         //更新oj
     35         t.oj=max(lson.oj,rson.oj);
     36         t.oj=max(t.oj,lson.oo+rson.jj);
     37         t.oj=max(t.oj,lson.oj+rson.oj);
     38     }
     39     void build(int l,int r,int rt)
     40     {
     41         if(l==r)
     42         {
     43             tree[rt].jo=tree[rt].oj=-inf;
     44             tree[rt].oo=tree[rt].jj=-inf;
     45             if(l&1)
     46             {
     47                 tree[rt].jj=a[l];
     48             }
     49             else
     50             {
     51                 tree[rt].oo=a[l];
     52             }
     53             return;
     54         }
     55         int mid=(l+r)/2;
     56         build(l,mid,LL(rt));
     57         build(mid+1,r,RR(rt));
     58         pushup(tree[rt],tree[rt<<1],tree[rt<<1|1]);
     59     }
     60     void updata(int l,int r,int rt,int pos,int valu)
     61     {
     62         if(l==r)
     63         {
     64             if(l&1)
     65                 tree[rt].jj=valu;
     66             else
     67                 tree[rt].oo=valu;
     68             return;
     69         }
     70         int mid=(l+r)>>1;
     71         if(pos<=mid)
     72             updata(l,mid,rt<<1,pos,valu);
     73         else
     74             updata(mid+1,r,rt<<1|1,pos,valu);
     75         pushup(tree[rt],tree[rt<<1],tree[rt<<1|1]);
     76     }
     77     void query(int l,int r,int rt,int st,int ed)
     78     {
     79         if(st<=l&&r<=ed)
     80         {
     81             pushup(tt,tt,tree[rt]);
     82             return;
     83         }
     84         int mid=(l+r)/2;
     85         if(st<=mid)
     86             query(l,mid,LL(rt),st,ed);
     87         if(mid<ed)
     88             query(mid+1,r,RR(rt),st,ed);
     89     }
     90 } seg;
     91 int main()
     92 {
     93     int T;
     94     scanf("%d",&T);
     95     while(T--)
     96     {
     97         scanf("%d%d",&n,&m);
     98         for(int i=1; i<=n; i++)
     99             scanf("%I64d",&a[i]);
    100         seg.build(1,n,1);
    101         for(int i=0; i<m; i++)
    102         {
    103             int op,a,b;
    104             scanf("%d%d%d",&op,&a,&b);
    105             if(op)
    106             {
    107                 seg.updata(1,n,1,a,b);
    108             }
    109             else
    110             {
    111                 tt.oo=tt.oj=tt.jo=tt.jj=-inf;
    112                 seg.query(1,n,1,a,b);
    113                 long long maxm=tt.oo;
    114                 maxm=max(maxm,tt.oj);
    115                 maxm=max(maxm,tt.jj);
    116                 maxm=max(maxm,tt.jo);
    117                 printf("%I64d
    ",maxm);
    118             }
    119         }
    120     }
    121     return 0;
    122 }
    View Code

    好几天没做线段树了,回家前就练线段树了!

    今天做的这道题很巧妙,只要了解做法就很好敲了。

    poj2828 BuyTickets

      题意:有N个人排队,每一个人都有一个val来对应,每一个后来人都会插入当前队伍的某一个位置pos。要求把队伍最后的状态输出。

       思路:首先,我们想到最后那个人n的位置肯定是固定的了,所以,我们要求第n-1个人的位置就要在第n个人位置固定的基础上再找第pos[n-1]个空位。

      以此类推,我们可以知道要得到最终状态,就要从后往前定位,先建树,树的每个节点存左右区间和该区间内的空位数,然后开始找位置,找到对应的位置,将该位置的空位数置为0,然后要向上更新树。。。是不是很简单~。~

      参考代码:

      

     1 #include<stdio.h>
     2 #include<algorithm>
     3 #include<string.h>
     4 using namespace std;
     5 #define LL(x) (x<<1)
     6 #define RR(x) (x<<1|1)
     7 #define MID(a,b) (a+((b-a)>>1))
     8 int n;
     9 int pos[200005],val[200005],res[200005];
    10 struct node
    11 {
    12     int lft,rht,valu;
    13     int mid()
    14     {
    15         return MID(lft,rht);
    16     }
    17 };
    18 struct Segtree
    19 {
    20     node tree[200005*4];
    21     void pushup(int rt)
    22     {
    23         tree[rt].valu=tree[LL(rt)].valu+tree[RR(rt)].valu;
    24     }
    25     void build(int l,int r,int rt)
    26     {
    27         tree[rt].lft=l;
    28         tree[rt].rht=r;
    29         tree[rt].valu=r-l+1;
    30         if(l!=r)
    31         {
    32             int mid=tree[rt].mid();
    33             build(l,mid,LL(rt));
    34             build(mid+1,r,RR(rt));
    35         }
    36     }
    37     int query(int p,int rt)
    38     {
    39         int lft=tree[rt].lft;
    40         int rht=tree[rt].rht;
    41         if(lft==rht)
    42         {
    43             tree[rt].valu=0;
    44             return lft;
    45         }
    46         else
    47         {
    48             int pos;
    49             if(tree[LL(rt)].valu>=p)
    50                 pos=query(p,LL(rt));
    51             else
    52                 pos=query(p-(tree[LL(rt)].valu),RR(rt));
    53             pushup(rt);
    54             return pos;
    55         }
    56     }
    57 } seg;
    58 int main()
    59 {
    60     while(scanf("%d",&n)!=EOF)
    61     {
    62         seg.build(0,n-1,1);
    63         for(int i=0; i<n; i++)
    64             scanf("%d%d",&pos[i],&val[i]);
    65         for(int i=n-1; i>=0; i--)
    66         {
    67             int p=seg.query(pos[i]+1,1);
    68             res[p]=val[i];
    69         }
    70         for(int i=0; i<n; i++)
    71         {
    72             if(i)
    73             {
    74                 printf(" %d",res[i]);
    75             }
    76             else
    77                 printf("%d",res[i]);
    78         }
    79         printf("
    ");
    80     }
    81     return 0;
    82 }
    View Code

     POJ 2481 Cows

      题意:有N头牛,每只牛有一个测试值[S,E],如果对于牛i和牛j来说,它们的测验值满足下面的条件则证明牛i比牛j强壮:Si <= Sj and Ej <= Ei and Ei - Si > Ej - Sj。现在已知每一头牛的测验值,要求输出每头牛有几头牛比其强壮。

      思路: 先将S从小到大排序,E从大到小排序,这样就可以保证在放入一个区间里,前面所以放下的区间的左端点都是小于等于它的。那么,这时候查询,有多少个区间的右端点是大于等于它的右端点的,就可以得出答案。
            需要注意的是,在查询的时候,如果当前区间和前面一个区间是完全相同的话,那么直接将前面的区间得到的答案赋给它就可以,不然,查询大于等于它的右端点的数目。

      如果在查询的时候,把相同的区间排除掉就可以了。

    参考代码:

      

      1 #include <set>
      2 #include <map>
      3 #include <list>
      4 #include <queue>
      5 #include <stack>
      6 #include <string>
      7 #include <math.h>
      8 #include <time.h>
      9 #include <vector>
     10 #include <stdio.h>
     11 #include <sstream>
     12 #include <string.h>
     13 #include <stdlib.h>
     14 #include <iostream>
     15 #include <algorithm>
     16 using namespace std;
     17 /***************************************/
     18 typedef vector<int> VI;
     19 typedef vector<char> VC;
     20 typedef vector<string> VS;
     21 typedef set<int> SI;
     22 typedef set<string> SS;
     23 typedef map<int ,int> MII;
     24 typedef map<string,int> MSI;
     25 typedef pair<int,int> PII;
     26 typedef vector<PII> VII;
     27 typedef vector<VI > VVI;
     28 /***************************************/
     29 #ifdef _WIN32
     30 #define ll __int64
     31 #else
     32 #define ll long long
     33 #endif
     34 #define MID(a,b) (a+((b-a)>>1))
     35 #define mem(a,b) memset(a,b,sizeof(a))
     36 #define all(x)  (x).begin(), (x).end()
     37 #define sz(x) ((int)(x).size())
     38 #define PB push_back
     39 #define MP make_pair
     40 #define LL(x) ((x)<<1)
     41 #define RR(x) ((x)<<1|1)
     42 #define sqr(x) ((x)*(x))
     43 #define pn()  printf("
    ")
     44 #define sqr(x) ((x)*(x))
     45 /***************************************/
     46 const int INF = 0x7f7f7f7f;
     47 const ll LINF = (1LL<<60);
     48 const double eps = 1e-8;
     49 const double PIE=acos(-1.0);
     50 const int dx[]= {0,-1,0,1};
     51 const int dy[]= {1,0,-1,0};
     52 const int fx[]= {-1,-1,-1,0,0,1,1,1};
     53 const int fy[]= {-1,0,1,-1,1,-1,0,1};
     54 /***************************************/
     55 void openfile()
     56 {
     57     freopen("data.in","rb",stdin);
     58     freopen("data.out","wb",stdout);
     59 }
     60 void Scan(int& res)
     61 {
     62     int flag=0;
     63     char ch;
     64     while(!(((ch=getchar())>='0'&&ch<='9')||ch=='-'))
     65         if(ch==EOF)
     66             res=INF;
     67     if(ch=='-')
     68         flag=1;
     69     else if(ch>='0'&&ch<='9')
     70         res=ch-'0';
     71     while((ch=getchar())>='0'&&ch<='9')
     72         res=res*10+ch-'0';
     73     res=flag?-res:res;
     74 }
     75 void Out(int a)
     76 {
     77     if(a>9)
     78         Out(a/10);
     79     putchar(a%10+'0');
     80 }
     81 void Out(ll a)
     82 {
     83     if(a>9)
     84         Out(a/10);
     85     putchar(a%10+'0');
     86 }
     87 /**********************The End OF The Template*****************/
     88 
     89 const int N=1e5+5;
     90 int res[N];
     91 struct cow
     92 {
     93     int s,e,id;
     94 } cows[N];
     95 struct node
     96 {
     97     int lft,rht,sum;
     98     int mid()
     99     {
    100         return MID(lft,rht);
    101     }
    102 };
    103 struct segtree
    104 {
    105     node tree[N*4];
    106     void build(int lft,int rht,int rt)
    107     {
    108         tree[rt].lft=lft;
    109         tree[rt].rht=rht;
    110         tree[rt].sum=0;
    111         if(lft!=rht)
    112         {
    113             int mid=tree[rt].mid();
    114             build(lft,mid,LL(rt));
    115             build(mid+1,rht,RR(rt));
    116         }
    117     }
    118     int query(int st,int ed,int rt)
    119     {
    120         int lft=tree[rt].lft;
    121         int rht=tree[rt].rht;
    122         if(st<=lft&&ed>=rht)
    123         {
    124             return tree[rt].sum;
    125         }
    126         else
    127         {
    128             int sum=0;
    129             int mid=tree[rt].mid();
    130             if(st<=mid)
    131                 sum+=query(st,ed,LL(rt));
    132             if(ed>mid)
    133                 sum+=query(st,ed,RR(rt));
    134             return sum;
    135         }
    136     }
    137     void updata(int pos,int ind)
    138     {
    139         tree[ind].sum++;
    140         if(tree[ind].lft==tree[ind].rht)
    141             return;
    142         else
    143         {
    144             int mid=tree[ind].mid();
    145             if(pos<=mid)
    146                 updata(pos,LL(ind));
    147             else
    148                 updata(pos,RR(ind));
    149         }
    150     }
    151 }seg;
    152 int cmp(cow x,cow y)
    153 {
    154     return x.s<y.s||(x.s==y.s&&x.e>y.e);
    155 }
    156 int main()
    157 {
    158     int n;
    159     int st,ed;
    160     while(scanf("%d",&n)!=EOF&&n)
    161     {
    162         for(int i=0; i<n; i++)
    163         {
    164             scanf("%d%d",&st,&ed);
    165             cows[i].s=st;
    166             cows[i].e=ed;
    167             cows[i].id=i;
    168         }
    169         sort(cows,cows+n,cmp);
    170         seg.build(0,N,1);
    171         for(int i=0; i<n; i++)
    172         {
    173             int p=cows[i].id,q=cows[i-1].id;
    174             if(i&&cows[i].s==cows[i-1].s&&cows[i].e==cows[i-1].e)
    175                 res[p]=res[q];
    176             else res[p]=seg.query(cows[i].e,N,1);
    177             seg.updata(cows[i].e,1);
    178         }
    179         for(int i=0; i<n; i++)
    180         {
    181             if(i)
    182                 printf(" %d",res[i]);
    183             else
    184                 printf("%d",res[i]);
    185         }
    186         printf("
    ");
    187     }
    188     return 0;
    189 }
    View Code

    二、成段更新

           简单的说明:成段更新需要用到延迟标记(或者说懒惰标记),简单来说就是每次更新的时候不要更新到底,用延迟标记使得更新延迟到下次需要更新or询问到的时候。延迟标记的意思是:这个区间的左右儿子都需要被更新,但是当前区间已经更新了。

      

    poj3468 A SimpleProblem with Integers(lazy思想详解)

      题意:给你N个数,Q个操作,操作有两种,‘Q a b ’是询问a~b这段数的和,‘C a b c’是把a~b这段数都加上c。

      思路:

        介绍Lazy思想:lazy-tag思想,记录每一个线段树节点的变化值,当这部分线段的一致性被破坏我们就将这个变化值传递给子区间,大大增加了线段树的效率。

        在此通俗的解释我理解的Lazy意思,比如现在需要对[a,b]区间值进行加c操作,那么就从根节点[1,n]开始调用update函数进行操作,如果刚好执行到一个子节点,它的节点标记为rt,这时tree[rt].l == a && tree[rt].r == b 这时我们可以一步更新此时rt节点的sum[rt]的值,sum[rt] += c * (tree[rt].r - tree[rt].l + 1),注意关键的时刻来了,如果此时按照常规的线段树的update操作,这时候还应该更新rt子节点的sum[]值,而Lazy思想恰恰是暂时不更新rt子节点的sum[]值,到此就return,直到下次需要用到rt子节点的值的时候才去更新,这样避免许多可能无用的操作,从而节省时间 。

        下面通过具体的代码来说明之,在此先介绍下代码中的函数说明:

        #define lson l,m,rt<<1
        #define rson m+1,r,rt<<1|1

        宏定义左儿子lson和右儿子rson,貌似用宏的速度要慢。

        PushUp(rt):通过当前节点rt把值递归向上更新到根节点

        PushDown(rt):通过当前节点rt递归向下去更新rt子节点的值

        rt表示当前子树的根(root),也就是当前所在的结点

        下面直接来介绍update函数,Lazy操作主要就是用在这里:

    void update(int c,int l,int r,int rt)//表示对区间[l,r]内的每个数均加c,rt是根节点
    {
        if(tree[rt].l == l && r == tree[rt].r)
        {
            add[rt] += c;
            sum[rt] += (__int64)c * (r-l+1);
            return;
        }
        if(tree[rt].l == tree[rt].r) return;
        PushDown(rt,tree[rt].r - tree[rt].l + 1);
        int m = tree[rt].mid();
        if(r <= m) update(c,l,r,rt<<1);
        else if(l > m) update(c,l,r,rt<<1|1);
        else
        {
            update(c,l,m,rt<<1);
            update(c,m+1,r,rt<<1|1);
        }
        PushUp(rt);
    }

        

    if(tree[rt].l == l && r == tree[rt].r) 这里就是用到Lazy思想的关键时刻 正如上面说提到的,这里首先更新该节点的sum[rt]值,然后更新该节点具体每个数值应该加多少即add[rt]的值,注意此时整个函数就运行完了,直接return,而不是还继续向子节点继续更新,这里就是Lazy思想,暂时不更新子节点的值。

    那么什么时候需要更新子节点的值呢?答案是在某部分update操作的时候需要用到那部分没有更新的节点的值的时候,这里可能有点绕口。这时就掉用PushDown()函数更新子节点的数值。

    void PushDown(int rt,int m)
    {
        if(add[rt])
        {
            add[rt<<1] += add[rt];
            add[rt<<1|1] += add[rt];
            sum[rt<<1] += add[rt] * (m - (m>>1));
            sum[rt<<1|1] += add[rt] * (m>>1);
            add[rt] = 0;//更新后需要还原
        }
    }

    PushDown就是从当前根节点rt向下更新每个子节点的值,这段代码读者可以自己好好理解,这也是Lazy的关键。

    下面再解释query函数,也就是用这个函数来求区间和

    __int64 query(int l,int r,int rt)
    {
        if(l == tree[rt].l && r == tree[rt].r)
        {
            return sum[rt];
        }
        PushDown(rt,tree[rt].r - tree[rt].l + 1);
        int m = tree[rt].mid();
        __int64 res = 0;
        if(r <= m) res += query(l,r,rt<<1);
        else if(l > m) res += query(l,r,rt<<1|1);
        else
        {
           res += query(l,m,rt<<1);
           res += query(m+1,r,rt<<1|1);
        }
        return res;
    }

    第一个if还是区间的判断和前面update的一样,到这里就可以知道答案了,所以就直接return。

    接下来的查询就需要用到rt子节点的值了,由于我们用了Lazy操作,这段的数值还没有更新,因此我们需要调用PushDown函数去更新之,满足if(add[rt])就说明还没有更新。

    参考代码:

      1 #include <set>
      2 #include <map>
      3 #include <list>
      4 #include <queue>
      5 #include <stack>
      6 #include <string>
      7 #include <math.h>
      8 #include <time.h>
      9 #include <vector>
     10 #include <stdio.h>
     11 #include <sstream>
     12 #include <string.h>
     13 #include <stdlib.h>
     14 #include <iostream>
     15 #include <algorithm>
     16 using namespace std;
     17 #define LL(x) (x<<1)
     18 #define RR(x) (x<<1|1)
     19 #define MID(a,b) (a+((b-a)>>1))
     20 const int N = 1e5 + 5;
     21 struct cow
     22 {
     23     int s, e, id;
     24 } cows[N];
     25 struct node
     26 {
     27     int lft, rht;
     28     long long sum,add;
     29     int mid()
     30     {
     31         return MID(lft, rht);
     32     }
     33 };
     34 struct segtree
     35 {
     36     node tree[N * 4];
     37     void pushup(int rt)
     38     {
     39         tree[rt].sum = tree[LL(rt)].sum + tree[RR(rt)].sum;
     40     }
     41     void pushdown(int rt, int m)
     42     {
     43         if (tree[rt].add)
     44         {
     45             tree[LL(rt)].add +=tree[rt].add;
     46             tree[RR(rt)].add += tree[rt].add;
     47             tree[LL(rt)].sum += tree[rt].add*(m-(m>>1));
     48             tree[RR(rt)].sum += tree[rt].add*(m >> 1);
     49             tree[rt].add = 0;
     50         }
     51     }
     52     void build(int lft, int rht, int rt)
     53     {
     54         tree[rt].lft = lft;
     55         tree[rt].rht = rht;
     56         tree[rt].sum = tree[rt].add = 0;
     57         if (lft == rht){
     58             scanf("%I64d", &tree[rt].sum);
     59             return;
     60         }
     61         else
     62         {
     63             int mid = tree[rt].mid();
     64             build(lft, mid, LL(rt));
     65             build(mid + 1, rht, RR(rt));
     66             pushup(rt);
     67         }
     68     }
     69     long long query(int st, int ed, int rt)
     70     {
     71         int lft = tree[rt].lft;
     72         int rht = tree[rt].rht;
     73         if (st == lft && ed == rht)
     74         {
     75             return tree[rt].sum;
     76         }
     77         pushdown(rt,rht-lft + 1);
     78         int mid = tree[rt].mid();
     79         long long res = 0;
     80         if (ed<= mid)
     81             res += query(st, ed, LL(rt));
     82         else if (st > mid)
     83             res += query(st, ed, RR(rt));
     84         else
     85         {
     86             res += query(st, mid, LL(rt));
     87             res += query(mid + 1, ed, RR(rt));
     88         }
     89         return res;
     90     }
     91     void update(int st, int ed, int rt, int add)
     92     {
     93         int lft = tree[rt].lft, rht = tree[rt].rht;
     94         if (st == lft && ed == rht)
     95         {
     96             tree[rt].add += add;
     97             tree[rt].sum += (long long)(rht - lft + 1) * add;
     98             return;
     99         }
    100         if (tree[rt].lft == tree[rt].rht)
    101             return;
    102         pushdown(rt, rht - lft + 1);
    103         int mid = tree[rt].mid();
    104         if (ed <= mid)
    105             update(st, ed, LL(rt), add);
    106         else if (st > mid)
    107             update(st, ed, RR(rt), add);
    108         else
    109         {
    110             update(st, mid, LL(rt), add);
    111             update(mid + 1, ed, RR(rt), add);
    112         }
    113         pushup(rt);
    114     }
    115 } seg;
    116 int main()
    117 {
    118     int n, m;
    119     scanf("%d%d", &n, &m);
    120     seg.build(1, n, 1);
    121     for (int i = 0; i < m; i++)
    122     {
    123         char op[2];
    124         scanf("%s", op);
    125         int a, b, c;
    126         if (op[0] == 'Q')
    127         {
    128             scanf("%d%d", &a, &b);
    129             printf("%I64d
    ", seg.query(a, b, 1));
    130         }
    131         else
    132         {
    133             scanf("%d%d%d", &a, &b, &c);
    134             seg.update(a, b, 1, c);
    135         }
    136     }
    137     return 0;
    138 }
    View Code

    hdu1698 Just a Hook

    题意:给你T组数据,N个数(初始时每个数的值为1),M个操作,每个操作把区间[a,b]里的数更新为c,问最后这N个数的和是多少。

    思路:比上题简单,在上题代码上稍加修改即可。

    参考代码:

      1 #include <set>
      2 #include <map>
      3 #include <list>
      4 #include <queue>
      5 #include <stack>
      6 #include <string>
      7 #include <math.h>
      8 #include <time.h>
      9 #include <vector>
     10 #include <stdio.h>
     11 #include <sstream>
     12 #include <string.h>
     13 #include <stdlib.h>
     14 #include <iostream>
     15 #include <algorithm>
     16 using namespace std;
     17 #define LL(x) (x<<1)
     18 #define RR(x) (x<<1|1)
     19 #define MID(a,b) (a+((b-a)>>1))
     20 const int N = 1e5 + 5;
     21 struct cow
     22 {
     23     int s, e, id;
     24 } cows[N];
     25 struct node
     26 {
     27     int lft, rht;
     28     long long sum, add;
     29     int mid()
     30     {
     31         return MID(lft, rht);
     32     }
     33 };
     34 struct segtree
     35 {
     36     node tree[N * 4];
     37     void pushup(int rt)
     38     {
     39         tree[rt].sum = tree[LL(rt)].sum + tree[RR(rt)].sum;
     40     }
     41     void pushdown(int rt, int m)
     42     {
     43         if (tree[rt].add)
     44         {
     45             tree[LL(rt)].add = tree[rt].add;
     46             tree[RR(rt)].add = tree[rt].add;
     47             tree[LL(rt)].sum = tree[rt].add * (m - (m >> 1));
     48             tree[RR(rt)].sum = tree[rt].add * (m >> 1);
     49             tree[rt].add = 0;
     50         }
     51     }
     52     void build(int lft, int rht, int rt)
     53     {
     54         tree[rt].lft = lft;
     55         tree[rt].rht = rht;
     56         tree[rt].add = 0;
     57         if (lft == rht)
     58             tree[rt].sum = 1;
     59         else {
     60             int mid = tree[rt].mid();
     61             build(lft, mid, LL(rt));
     62             build(mid + 1, rht, RR(rt));
     63             pushup(rt);
     64         }
     65     }
     66     /*long long query(int st, int ed, int rt)
     67     {
     68         int lft = tree[rt].lft;
     69         int rht = tree[rt].rht;
     70         if (st == lft && ed == rht)
     71         {
     72             return tree[rt].sum;
     73         }
     74         pushdown(rt, rht - lft + 1);
     75         int mid = tree[rt].mid();
     76         long long res = 0;
     77         if (ed <= mid)
     78             res += query(st, ed, LL(rt));
     79         else if (st > mid)
     80             res += query(st, ed, RR(rt));
     81         else
     82         {
     83             res += query(st, mid, LL(rt));
     84             res += query(mid + 1, ed, RR(rt));
     85         }
     86         return res;
     87     }*/
     88     void update(int st, int ed, int rt, int c)
     89     {
     90         int lft = tree[rt].lft, rht = tree[rt].rht;
     91         if (st == lft && ed == rht)
     92         {
     93             tree[rt].add= c;
     94             tree[rt].sum = (long long)(rht - lft + 1) *c;
     95             return;
     96         }
     97         if (tree[rt].lft == tree[rt].rht)
     98             return;
     99         pushdown(rt, rht - lft + 1);
    100         int mid = tree[rt].mid();
    101         if (ed <= mid)
    102             update(st, ed, LL(rt), c);
    103         else if (st > mid)
    104             update(st, ed, RR(rt), c);
    105         else
    106         {
    107             update(st, mid, LL(rt), c);
    108             update(mid + 1, ed, RR(rt), c);
    109         }
    110         pushup(rt);
    111     }
    112 } seg;
    113 int main()
    114 {
    115     int T;
    116     int cas=0;
    117     scanf("%d", &T);
    118     while (T--)
    119     {
    120         cas++;
    121         int n, m;
    122         scanf("%d%d", &n, &m);
    123         seg.build(1, n, 1);
    124         while (m--)
    125         {
    126             int a, b, c;
    127             scanf("%d%d%d", &a, &b, &c);
    128             seg.update(a, b, 1, c);
    129         }
    130         printf("Case %d: The total value of the hook is %I64d.
    ",cas,seg.tree[1].sum);
    131     }
    132     return 0;
    133 }
    View Code
  • 相关阅读:
    0~n-1中缺失的数字
    仅仅反转字母
    字符串相加
    反转字符串&反转字符串中的元音字母
    python OrderedDict类&LRU缓存机制练习题
    协程greenlet、gevent、猴子补丁
    生产者与消费者(两个线程之间的通信---队列实现)
    jquery的on()
    Python之内置类型
    Python之比较运算符
  • 原文地址:https://www.cnblogs.com/PJQOOO/p/4660854.html
Copyright © 2020-2023  润新知