• 线段树学习笔记


    神牛传送门:

    http://www.notonlysuccess.com/index.php/segment-tree-complete/

    再加一个(风格是notonlysuccess的风格,写的很骚...):

    http://www.cnblogs.com/wuyiqi/tag/%E7%BA%BF%E6%AE%B5%E6%A0%91%E5%92%8C%E6%A0%91%E7%8A%B6%E6%95%B0%E7%BB%84/

    +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

    线段树学习全记录:

    代码风格:notonlysuccess

     

    +++单点操作

    poj--2828 Buy Tickets(线段树功能:单点更新)

    题意:人们一个一个的来排队并插队,按人到来的顺序给出每个人插队的位置(插在第几个人后面),并告知每个人的id号,输出最终队伍的情况。

    分析:可以用线段树,从最后来的一个人开始向来得更早的人遍历,这样pos(插在第几个人后面)的意义就变成了,前面有多少个空位。线段树上每个节点中存储的是当前时刻,该区间有多少空位。 

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #define lson l,m,rt<<1
     6 #define rson m+1,r,rt<<1|1
     7 
     8 using namespace std;
     9 
    10 #define MAXN 200005
    11 
    12 //sum表示这个区间有多少个空位
    13 
    14 int sum[MAXN<<2];    //原数据量扩大4倍用int数组建树
    15 int pos[MAXN],val[MAXN],ans[MAXN];
    16 
    17 void build(int l,int r,int rt)
    18 {
    19     sum[rt]=r-l+1;//初始化时空位数
    20     if(l==r)   
    21         return;
    22       int m = (l+r)>>1;
    23     build(lson);  //递归建左子树
    24     build(rson);//递归建右子树
    25 }
    26 
    27 int id;
    28 //每次更新即将找到前面敲好p个空位
    29 void update(int p,int l,int r,int rt)
    30 {
    31     sum[rt]--;//更新到l-->r这段时必然将占有原来的一个空位
    32 
    33     if (l==r)    //已经到最底端
    34     {
    35         id=l;//此时l前面敲好有p个空位
    36         return ;
    37     }
    38     int m = (l + r) >> 1;
    39     if (p<sum[rt<<1])       //左边的空位有多余p个空位
    40         update(p ,lson);
    41     else    
    42     {
    43         p-=sum[rt<<1];//减去左边的空位总数,假如:p=3,sum[rt<<1]=1,则递归调用右子树时的p值应该更新为2。
    44         update(p , rson);
    45     }
    46 }
    47 
    48 int main()
    49 {
    50     int N;
    51     while(scanf("%d",&N)!=EOF)
    52     {
    53         build(1,N,1);
    54         for(int i=1;i<=N;i++)
    55         {
    56             ans[i]=0;
    57             scanf("%d%d",&pos[i],&val[i]);
    58         }
    59 
    60         for(int i=N;i>0;i--)
    61         {
    62             update(pos[i],1,N,1);
    63             ans[id]=val[i];
    64         }
    65             
    66         for(int i=1;i<=N;i++)
    67         {
    68             if(i==1)
    69                 printf("%d",ans[i]);
    70             else
    71                 printf(" %d",ans[i]);
    72         }
    73 
    74         printf("\n");
    75     }
    76     return 0;
    77 }

     

    hdu 1166 敌兵布阵线段树功能:update:单点增减 query:区间求和

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 
     5 using namespace std;
     6 
     7 #define ls rt<<1
     8 #define rs rt<<1|1
     9 #define lson l,m,ls
    10 #define rson m+1,r,rs
    11 #define mid (l+r)>>1
    12 
    13 #define MAXN  55555
    14 
    15 int sum[MAXN<<2];    //原数据量扩大4倍用int数组建树
    16 
    17 void PushUp(int rt)
    18 {
    19   sum[rt] = sum[ls] + sum[rs];
    20 }
    21 
    22 void build(int l,int r,int rt)
    23 {
    24   if(l==r)    //叶子节点,返回
    25   {
    26     scanf("%d",&sum[rt]); //直接在这里输入建树
    27     return;
    28   }
    29   int m = mid;
    30   build(lson);  //递归建左子树
    31   build(rson);//递归建右子树
    32   PushUp(rt);
    33 }
    34 //update
    35 void update(int p,int add,int l,int r,int rt)
    36 {
    37     if (l==r)    //节点区间[l,r]被目标区间[L,R]包含
    38     {
    39         sum[rt] += add;
    40         return ;
    41     }
    42     int m = (l + r) >> 1;
    43     if (p<= m)       //左孩子包含有需要的信息
    44         update(p , add , lson);
    45     else      //右孩子包含有需要的信息
    46         update(p , add , rson);
    47     PushUp(rt);     //sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    48 }
    49 
    50 int query(int L,int R,int l,int r,int rt)
    51 {
    52   if (L <= l && r <= R)    //节点区间[l,r]被目标区间[L,R]包含
    53   {
    54     return sum[rt];
    55   }
    56   int m = mid;
    57   int ret = 0;
    58   if (L <= m)       //左孩子包含有需要的信息
    59     ret += query(L , R , lson);
    60   if (m < R)        //右孩子包含有需要的信息
    61     ret += query(L , R , rson);
    62   return ret;
    63 }
    64 
    65 int main()
    66 {
    67     int T,n,set=1;
    68     scanf("%d",&T);
    69     while(T--)
    70     {
    71         printf("Case %d:\n",set++);
    72         scanf("%d",&n);
    73         build(1 , n , 1);
    74         char op[10];
    75         while(scanf("%s",&op)==1)
    76         {
    77             if(op[0]=='E')
    78                 break;
    79             int a,b;
    80             scanf("%d%d",&a,&b);
    81             if(op[0]=='A')
    82                 update(a , b , 1 , n , 1);
    83             else if(op[0]=='S')
    84                 update(a,-b,1,n,1);
    85             else if(op[0]='Q')
    86                 printf("%d\n",query(a , b , 1 , n , 1));
    87         }
    88     }
    89     return 0;
    90 }

    hdu 1754 I hate it线段树功能:update:单点修改 query:区间最值 

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 
     6 using namespace std;
     7 
     8 #define ls rt<<1
     9 #define rs rt<<1|1
    10 #define lson l,m,ls
    11 #define rson m+1,r,rs
    12 #define mid (l+r)>>1
    13 
    14 #define MAXN 200005
    15 #define Max(x,y) ((x)>(y)?(x):(y))
    16 
    17 int MAX[MAXN<<2];    //原数据量扩大4倍用int数组建树
    18 
    19 void PushUp(int rt)
    20 {
    21   MAX[rt] = Max(MAX[ls] , MAX[rs]);
    22 }
    23 
    24 void build(int l,int r,int rt)
    25 {
    26   if(l==r)    //叶子节点,返回
    27   {
    28     scanf("%d",&MAX[rt]); //直接在这里输入建树
    29     return;
    30   }
    31   int m = mid;
    32   build(lson);  //递归建左子树
    33   build(rson);//递归建右子树
    34   PushUp(rt);
    35 }
    36 void update(int p,int q,int l,int r,int rt)
    37 {
    38     if (l==r)    //节点区间[l,r]被目标区间[L,R]包含
    39     {
    40         MAX[rt]= q;
    41         return ;
    42     }
    43     int m = mid;
    44     if (p<= m)       //左孩子包含有需要的信息
    45         update(p , q , lson);
    46     else      //右孩子包含有需要的信息
    47         update(p , q , rson);
    48     PushUp(rt);     //sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    49 }
    50 
    51 int query(int L,int R,int l,int r,int rt)
    52 {
    53   if (L <= l && r <= R)    //节点区间[l,r]被目标区间[L,R]包含
    54   {
    55     return MAX[rt];
    56   }
    57   int m = (l + r) >> 1;
    58   int ret = 0;
    59   if (L <= m)       //左孩子包含有需要的信息
    60     ret = max(ret,query(L , R , lson));
    61   if (m < R)        //右孩子包含有需要的信息
    62     ret = max(ret,query(L , R , rson));
    63   return ret;
    64 }
    65 
    66 int main()
    67 {
    68     int T,n;
    69     while(scanf("%d%d",&n,&T)==2)
    70     {
    71         build(1 , n , 1);
    72         char op[10];
    73         while(T--)
    74         {
    75             scanf("%s",&op);
    76             int a,b;
    77             scanf("%d%d",&a,&b);
    78             if(op[0]=='U')
    79                 update(a , b , 1 , n , 1);
    80             else if(op[0]='Q')
    81                 printf("%d\n",query(a , b , 1 , n , 1));
    82         }
    83     }
    84     return 0;
    85 }

    hdu 1394/zoj 1484 Minimum Inversion Number 线段树功能:update:单点增减 query:区间求和

    题意:给一个长度为n的序列(n<=5000),由0~n-1的数字组成。每次把最左边的数挪到最右边形成一个新的序列。那么一共可以形成n个序列。求这n个序列里面最小的逆序数是多少。

    分析:用数组a[0~n-1]来存原始数据。只需求出原始序列的逆序数sum,然后对于a[i](0<= i <n-1),每挪一个,用sum减去挪之前它右边比它小的数的个数(也就是a[i])、再用sum加上挪之后左边比它大的数的个数(也就是n-a[i]-1),就是挪了a[i]的逆序数了

    ps:求逆序数可以用线段树,树状数组,归并排序等。这题也可以暴力。

    View Code
     1 //线段树实现功能:求逆序数
     2 #include <iostream>
     3 #include <cstdio>
     4 #include <cstring>
     5 
     6 using namespace std;
     7 
     8 #define lson l,m,rt<<1
     9 #define rson m+1,r,rt<<1|1
    10 #define MAXN 5005
    11 #define MIN(x,y) ((x)>(y)?(y):(x))
    12 
    13 int sum[MAXN<<2];
    14 
    15 void PushUp(int rt)
    16 {
    17     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    18 }
    19 
    20 void build(int l,int r,int rt)
    21 {
    22     sum[rt]=0;//sum表示该区间数字出现的个数,
    23     if(l==r)
    24         return;
    25     int m=(r+l)>>1;
    26     build(lson);
    27     build(rson);
    28 }
    29 
    30 void update(int p,int l,int r,int rt)
    31 {
    32     if(l==r)
    33     {
    34         sum[rt]++;
    35         return;
    36     }
    37     int m = (l+r) >> 1;
    38     if(p <= m )
    39         update(p,lson);
    40     else
    41         update(p,rson);
    42     PushUp(rt);
    43 }
    44 
    45 int query(int L,int R,int l,int r,int rt)
    46 {
    47     if(L <= l && r <= R)//当前点代表的区间在要查找的区间之内
    48         return sum[rt];
    49     int m = (l + r) >> 1;
    50     int ret = 0;
    51     if(L <= m) //左边区间包含有要查询的点
    52         ret += query(L, R, lson);
    53     if(m < R)    //右边区间包含
    54         ret += query(L, R, rson);
    55     return ret;
    56 }
    57 
    58 int n,x[MAXN];
    59 
    60 int main()
    61 {
    62     int i,j;
    63     while(scanf("%d",&n)!=EOF)
    64     {
    65         build(0,n-1,1);
    66         int sum=0;
    67         for(i=0;i<n;i++)
    68         {
    69             scanf("%d",&x[i]);
    70             //查询比x[i]大的数出现了多少个。
    71             //即x[i]能产生的逆序对的个数
    72             sum+=query(x[i],n-1,0,n-1,1);
    73             //将x[i]更新入线段树中
    74             update(x[i],0,n-1,1);
    75         }
    76 
    77         int ans=sum;
    78 
    79         //!!对任意一列逆序数,设其中第一个为a
    80         //则a之后比a小的数有0,1,...a-1即a个。(ps:因为是连续的前n个数求你逆序对...没看清题意..唉..)
    81 //比a大的有(n-x[i]-1)个
    82         for(i=0;i<n;i++)
    83         {
    84             sum = (sum - x[i]) + (n - x[i] -1);
    85             ans = MIN(ans,sum);
    86         }
    87 
    88         printf("%d\n",ans);
    89     }
    90     return 0;
    91 }

    hdu 2795  Billboard(线段树功能:update:无(包含在query()里) query:区间最值)

    题意:h*w的木板,放进一些1*L的物品,求每次放空间能容纳且最上边的位子

    分析:每次找到最大值的位子,然后减去L

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 
     6 using namespace std;
     7 
     8 #define ls rt<<1
     9 #define rs rt<<1|1
    10 #define lson l,m,rt<<1
    11 #define rson m+1,r,rt<<1|1
    12 #define mid (l+r)>>1
    13 
    14 #define MAXN 200005
    15 #define Max(x,y) ((x)>(y)?(x):(y))
    16 
    17 int MAX[MAXN<<2];    //原数据量扩大4倍用int数组建树
    18 int h,w,n;
    19 void PushUp(int rt)
    20 {
    21   MAX[rt] = Max(MAX[ls] , MAX[rs]);
    22 }
    23 void build(int l,int r,int rt)
    24 {    
    25     MAX[rt]=w; 
    26     if(l==r)    //叶子节点,返回
    27         return;
    28     int m= (l+r)>>1;
    29     build(lson);  //递归建左子树
    30     build(rson);//递归建右子树
    31 }
    32 
    33 int query(int x,int l,int r,int rt)
    34 {
    35     if(l==r) 
    36     {
    37          MAX[rt]-=x;
    38          return l;
    39     }
    40     int m=mid;
    41     int ret=0;
    42     if(MAX[ls] >= x)       
    43         ret= query(x, lson); 
    44     else
    45         ret= query(x, rson);
    46     PushUp(rt);
    47     return ret;
    48 }
    49 int main()
    50 {
    51     int x;
    52     while(scanf("%d%d%d",&h,&w,&n)==3)
    53     {
    54         if(h>n)
    55             h=n;
    56         build(1, h, 1);
    57         while(n--)
    58         {
    59             scanf("%d",&x);
    60             if(x>MAX[1])
    61                 printf("-1\n");
    62             else
    63                 printf("%d\n",query(x, 1, h, 1));
    64         }
    65     }
    66     return 0;
    67 }

    poj 2182  hdu 2711 lost cows(线段树功能:update:单点更新区间空位数)

    题意:1~n,表示从第二个数开始,这个数前面有多少个比自己小的数。求这个序列。

    分析:从后往前插入线段树,线段树维护区间内空位的个数

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <algorithm>
     5 
     6 using namespace std;
     7 
     8 #define ls rt<<1
     9 #define rs rt<<1|1
    10 #define lson l,m,ls
    11 #define rson m+1,r,rs
    12 #define mid (l+r)>>1
    13 
    14 #define MAXN 8010
    15 
    16 int sum[MAXN<<2];
    17 int ans[MAXN];
    18 int num[MAXN];
    19 
    20 void build(int l,int r,int rt)
    21 {
    22     sum[rt]=r-l+1;
    23     if(l==r) return;
    24     int m=mid;
    25     build(lson);
    26     build(rson);
    27 }
    28 
    29 void PushUp(int rt)
    30 {
    31     sum[rt] = sum[ls]+sum[rs];
    32 }
    33 
    34 int k;
    35 
    36 void update(int p,int l,int r,int rt)
    37 {
    38     sum[rt]--;
    39     if(l==r)
    40     {
    41         ans[k++]=l;
    42         return ;
    43     }
    44     int m=mid;
    45     if(p<=sum[ls])
    46     {
    47         //sum[rt<<1|1]--;
    48         update(p,lson);
    49     }
    50     else if(p>sum[ls])
    51     {
    52         p-=sum[ls];
    53         update(p,rson);
    54     }
    55 }
    56 
    57 
    58 int main()
    59 {
    60     int n;
    61     while(scanf("%d",&n) != EOF)
    62     {
    63         build(1,n,1);
    64         for(int i=2;i<=n;i++)
    65             scanf("%d",&num[i]);
    66         k=0;
    67         for(int i=n;i>=2;i--)
    68             update(num[i]+1,1,n,1);
    69         update(1,1,n,1);
    70         for(int i=n-1;i>=0;i--)
    71             printf("%d\n",ans[i]);
    72     }
    73     return 0;
    74 }

     +++成段操作(lazy_tag:就是每次更新的时候在最上层满足更新条件时就更新,而不继续更新儿子,直到查询到此父亲的时候再更新儿子)

     

     hdu 1698 just a Hook线段树功能:update:成段替换

    题意:    给定一个长度为N(N <= 100000)的数列Si,紧接着Q(1 <= Q <= 100000)条操作,每条操作将[A, B]的区间颜色改成C(权值为C),颜色C最多三种,问最后所有数的权值总和。

    分析:    线段树的区间修改,还是利用lazy思想。线段树结点维护一个col域和一个sum域,col要么是-1表示当前结点有多种颜色,要么是颜色的编号,每次插入到完全覆盖时在该结点的col域上打上一个标记,表示当前颜色,计算当前结点的sum值。如果当前结点的颜色和插入的颜色相同,说明不必再往下插入了。如果没有完全覆盖,并且当前结点的颜色单一,那么直接将父亲的值传递给而两个儿子,还是同样的道理,之前的儿子如果有lazy标记,肯定是在当前标记之前,所以直接覆盖即可。最后通过两个儿子的权值计算当前子树的权值。  

    View Code
     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 
     6 using namespace std;
     7 
     8 #define lson l,m,rt<<1
     9 #define rson m+1,r,rt<<1|1
    10 #define MAXN 100010
    11 int sum[MAXN<<2];    //区间总的value
    12 int col[MAXN<<2];    //lazy_tag 即每次染色后该区间的价值
    13 
    14 void PushUp(int rt)
    15 {
    16     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
    17 }
    18 
    19 void PushDown(int rt,int m)//m是父亲区间长度
    20 {
    21     if(col[rt])//更新孩子
    22     {
    23         col[rt<<1]=col[rt];
    24         col[rt<<1|1]=col[rt];
    25         sum[rt<<1]=col[rt] * (m-(m>>1));
    26         sum[rt<<1|1]=col[rt] *(m>>1);
    27         col[rt]=0;
    28     }
    29 }
    30 
    31 void build(int l,int r,int rt)
    32 {
    33     col[rt]=0;
    34       if(l==r)    //叶子节点,返回
    35     {
    36         sum[rt]=1;
    37         return;
    38     }
    39       int m = (l+r)>>1;
    40       build(lson);  //递归建左子树
    41       build(rson);//递归建右子树
    42       PushUp(rt);
    43 }
    44 //update
    45 void update(int L,int R,int c,int l,int r,int rt)
    46 {
    47     if (L<= l && r<=R)    //节点区间[l,r]被目标区间[L,R]包含
    48     {
    49         col[rt]=c;
    50         sum[rt]= c*(r-l+1);
    51         return ;
    52     }
    53     PushDown(rt,r-l+1);
    54     int m = (l+r)>>1;
    55     if(L<=m)
    56         update(L,R,c,lson);
    57     if(m<R)
    58         update(L,R,c,rson);
    59     PushUp(rt);
    60 }
    61 
    62 
    63 int main()
    64 {
    65     int t,n,Q,a,b,c,set=1;
    66     scanf("%d",&t);
    67     while(t--)
    68     {
    69         scanf("%d",&n);
    70         build(1,n,1);
    71         scanf("%d",&Q);
    72         while(Q--)
    73         {
    74             scanf("%d%d%d",&a,&b,&c);
    75             update(a,b,c,1,n,1);
    76         }
    77 
    78         printf("Case %d: The total value of the hook is %d.\n",set++,sum[1]);
    79     }
    80     return 0;
    81 }

     poj 3468 A Simple Problem with Integers(线段树功能:update:成段增减 query:区间求和)

    View Code
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 
      6 using namespace std;
      7 
      8 #define ls rt<<1
      9 #define rs rt<<1|1
     10 #define lson l,m,rt<<1
     11 #define rson m+1,r,rt<<1|1
     12 #define mid (l+r)>>1
     13 
     14 #define MAXN 100100
     15 long long  sum[MAXN<<2];    //原数据量扩大4倍用int数组建树
     16 long long  add[MAXN<<2];
     17 
     18 void PushUp(int rt)
     19 {
     20     sum[rt]=sum[rt<<1]+sum[rt<<1|1];
     21 }
     22 
     23 void PushDown(int rt,int m)//m是父亲区间长度
     24 {
     25     if(add[rt])
     26     {
     27         add[ls]+=add[rt];
     28         add[rs]+=add[rt];
     29         sum[ls]+=add[rt] * (m-(m>>1));
     30         sum[rs]+=add[rt] *(m>>1);
     31         add[rt]=0;
     32     }
     33 }
     34 
     35 void build(int l,int r,int rt)
     36 {
     37     add[rt]=0;
     38       if(l==r)    //叶子节点,返回
     39       {
     40            scanf("%lld",&sum[rt]); //直接在这里输入建树
     41         return;
     42       }
     43       int m = mid;
     44       build(lson);  //递归建左子树
     45       build(rson);//递归建右子树
     46       PushUp(rt);
     47 }
     48 //update
     49 void update(int L,int R,int c,int l,int r,int rt)
     50 {
     51     if (L<= l && r<=R)    //节点区间[l,r]被目标区间[L,R]包含
     52     {
     53         add[rt]+=(long long)c;
     54         sum[rt]+= (long long )c*(r-l+1);
     55         return ;
     56     }
     57     PushDown(rt,r-l+1);
     58     int m = mid;
     59     if(L<=m)
     60         update(L,R,c,lson);
     61     if(m<R)
     62         update(L,R,c,rson);
     63     PushUp(rt);
     64 }
     65 
     66 long long  query(int L,int R,int l,int r,int rt)
     67 {
     68      if (L <= l && r <= R)    //节点区间[l,r]被目标区间[L,R]包含
     69       {
     70             return sum[rt];
     71      }
     72     PushDown(rt,r-l+1);
     73      int m = mid;
     74      long long  ret = 0;
     75      if (L <= m)       //左孩子包含有需要的信息
     76            ret +=query(L , R , lson);
     77       if (m < R)        //右孩子包含有需要的信息
     78            ret +=query(L , R , rson);
     79      return ret;
     80 }
     81 
     82 
     83 int main()
     84 {
     85     int N,Q;
     86     scanf("%d%d",&N,&Q);
     87     build(1,N,1);
     88     int a,b,d;
     89     char c[2];
     90     for(int i=0;i<Q;i++)
     91     {
     92         scanf("%s",&c);
     93         if(c[0]=='Q')
     94         {    
     95             scanf("%d%d",&a,&b);
     96             printf("%lld\n",query(a,b,1,N,1));
     97         }
     98         else
     99         {
    100             scanf("%d%d%d",&a,&b,&d);
    101             update(a,b,d,1,N,1);
    102         }    
    103     }
    104     return 0;
    105 }

     

    poj 2528 Mayor's posters(线段树功能:uodate:成段替换)

     ++离散化(notonlysuccess说的很详细)

    View Code
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 
      6 using namespace std;
      7 
      8 #define ls rt<<1
      9 #define rs rt<<1|1
     10 #define lson l,m,rt<<1
     11 #define rson m+1,r,rt<<1|1
     12 #define mid (l+r)>>1
     13 
     14 #define MAXN 11111
     15 
     16 int col[MAXN<<4];
     17 bool hash[MAXN];
     18 int li[MAXN],ri[MAXN];
     19 int X[MAXN<<3];
     20 int cnt;
     21 
     22 void PushDown(int rt)
     23 {
     24     if(col[rt]!=-1)
     25     {
     26         col[ls] = col[rs] = col[rt];
     27         col[rt] = -1;
     28     }
     29 }
     30 void update(int L,int R,int c,int l,int r,int rt)
     31 {
     32     if(L<=l && r<=R)
     33     {
     34         col[rt]=c;
     35         return;
     36     }
     37     PushDown(rt);
     38     int m=mid;
     39     if(L<=m)
     40         update(L,R,c,lson);
     41     if(m<R)
     42         update(L,R,c,rson);
     43 }
     44 
     45 void query(int l,int r,int rt)
     46 {
     47     if(col[rt] != -1)
     48     {
     49         if(!hash[col[rt]]) cnt++;
     50         hash[col[rt]] = true;
     51         return;
     52     }
     53 
     54     if(l == r) return;
     55     int m = mid;
     56     query(lson);
     57     query(rson);
     58 }
     59 
     60 int Bin(int key,int n,int X[])
     61 {
     62     int l = 0,r = n-1;
     63     while(l<=r)
     64     {
     65         int m = (l+r)>>1;
     66         if(X[m]==key) return m;
     67         if(X[m] < key) 
     68             l=m+1;
     69         else
     70             r=m-1;
     71     }
     72     return -1;
     73 }
     74 
     75 int main()
     76 {
     77     int t,n;
     78     scanf("%d",&t);
     79     while(t--)
     80     {
     81         scanf("%d",&n);
     82         int nn=0;
     83 
     84         for(int i=0;i<n;i++)
     85         {
     86             scanf("%d%d",&li[i],&ri[i]);
     87             X[nn++]=li[i];
     88             X[nn++]=ri[i];
     89         }
     90         sort(X,X+nn);
     91         int m=1;
     92         for(int i=1;i<nn;i++)
     93             if(X[i]!=X[i-1])
     94                 X[m++]=X[i];
     95 
     96         for(int i=m-1;i>0;i--)
     97             if(X[i]!=X[i-1]+1)
     98                 X[m++]=X[i-1]+1;
     99         sort(X,X+m);
    100 
    101         memset(col,-1,sizeof(col));
    102 
    103         for(int i=0;i<n;i++)
    104         {
    105             int l=Bin(li[i],m,X);
    106             int r=Bin(ri[i],m,X);
    107             update(l,r,i,0,m,1);
    108         }
    109         cnt=0;
    110         memset(hash,false,sizeof(hash));
    111         query(0,m,1);
    112 
    113         printf("%d\n",cnt);
    114     }
    115     return 0;
    116 }

     

    poj 3225 Help with Intervals(线段树功能:update:成段替换,区间异或

    notonlysuccess说的也很详细

    View Code
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <algorithm>
      5 
      6 using namespace std;
      7 
      8 #define ls rt<<1
      9 #define rs rt<<1|1
     10 #define lson l,m,rt<<1
     11 #define rson m+1,r,rt<<1|1
     12 #define mid (l+r)>>1
     13 
     14 #define MAXN 140000
     15 bool hash[MAXN+1];
     16 int cover[MAXN<<2];
     17 int XOR[MAXN<<2];
     18 
     19 void FXOR(int rt)
     20 {
     21     if(cover[rt] != -1)//表示这个区间被覆盖
     22         cover[rt] ^= 1;
     23     else
     24         XOR[rt] ^= 1;
     25 }
     26 
     27 void PushDown(int rt)
     28 {
     29     if(cover[rt] != -1)//表示此区间被覆盖,故无论XOR标记是否存在,孩子都被覆盖
     30     {
     31         cover[ls] = cover[rs] = cover[rt];
     32         XOR[ls] = XOR[rs] =0;
     33         cover[rt] = -1;
     34     }
     35 
     36     if(XOR[rt])
     37     {
     38         FXOR(ls);
     39         FXOR(rs);
     40         XOR[rt]=0;
     41     }
     42 }
     43 
     44 void update(char op,int L,int R,int l,int r,int rt)
     45 {
     46     if(L <= l && r <=R)
     47     {
     48         if(op == 'U')
     49         {
     50             cover[rt]=1;
     51             XOR[rt]=0;
     52         }
     53         else if(op=='D')
     54         {
     55             cover[rt]=0;
     56             XOR[rt]=0;
     57         }
     58         else if(op=='C' || op=='S')
     59             FXOR(rt);
     60         return;
     61     }
     62 
     63     PushDown(rt);
     64     int m=mid;
     65     if(L<=m)
     66         update(op,L,R,lson);
     67     else if(op=='I' || op=='C')
     68         XOR[ls]=cover[ls] =0;
     69     if(m<R)
     70         update(op,L,R,rson);
     71     else if(op=='I' || op=='C')
     72         XOR[rs]=cover[rs]=0;
     73 }
     74 
     75 void query(int l,int r,int rt)
     76 {
     77     if(cover[rt]==1)
     78     {
     79         for(int i=l;i<=r;i++)
     80             hash[i]=1;
     81     }
     82     else if(!cover[rt])
     83         return ;
     84     if(l==r) return;
     85     PushDown(rt);
     86     int m=mid;
     87     query(lson);
     88     query(rson);
     89 }
     90 
     91 int main()
     92 {
     93     cover[1]=XOR[1]=0;
     94     char op,l,r;
     95     int a,b;
     96     while(scanf("%c %c%d,%d%c\n",&op,&l,&a,&b,&r)!=EOF)
     97     {
     98         a<<=1,b<<=1;
     99         if(l=='(')a++;
    100         if(r==')')b--;
    101         if(a>b)//
    102         {
    103             if(op=='C' || op=='I')
    104                 cover[1]=XOR[1]=0;
    105         }
    106         else
    107             update(op,a,b,0,MAXN,1);
    108     }
    109     query(0,MAXN,1);
    110     bool flag =0;
    111     int s=-1,e;
    112     for(int i=0;i<=MAXN;i++)
    113     {
    114         if(hash[i])
    115         {
    116             if(s==-1)
    117                 s=i;
    118             e=i;
    119         }
    120         else
    121         {
    122             if(s != -1)
    123             {
    124                 if(flag)
    125                     printf(" ");
    126                 flag=true;
    127                 printf("%c%d,%d%c",s&1?'(':'[',s>>1,(e+1)>>1,e&1?')':']');
    128                 s=-1;
    129             }
    130         }
    131     }
    132     if(!flag)printf("empty set");
    133     puts("");
    134     return 0;
    135 }

    poj 1436 Horizontally Visible Segments(++++)

     

    View Code
      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <cmath>
      5 #include <algorithm>
      6 #include <vector>
      7 
      8 using namespace std;
      9 
     10 #define ls rt<<1
     11 #define rs rt<<1|1
     12 #define lson l,m,rt<<1
     13 #define rson m+1,r,rt<<1|1
     14 #define mid (l+r)>>1
     15 
     16 #define MAXN 8010
     17 
     18 int cover[MAXN<<4];
     19 int hash[MAXN<<1];
     20 vector<int> V[MAXN<<1];
     21 
     22 struct v_seg
     23 {
     24     int s,t;
     25     int x;
     26 }ss[MAXN];
     27 
     28 int cmp(v_seg a,v_seg b)
     29 {
     30     return a.x<b.x;
     31 }
     32 
     33 void PushDown(int rt)
     34 {
     35     if(cover[rt] != -1)
     36     {
     37         cover[ls]=cover[rs]=cover[rt];
     38         cover[rt] = -1;
     39     }
     40 }
     41 
     42 void update(int L,int R,int id,int l,int r,int rt)
     43 {
     44     if(L<=l && r<=R)
     45     {
     46         cover[rt]=id;
     47         return;
     48     }
     49     PushDown(rt);
     50     int m=mid;
     51     if(L<=m)
     52         update(L,R,id,lson);
     53     if(R>m)
     54         update(L,R,id,rson);
     55 }
     56 
     57 void query(int L,int R,int id,int l,int r,int rt)
     58 {
     59     if(cover[rt] != -1)
     60     {
     61         if(hash[cover[rt]] != id)
     62         {
     63             hash[cover[rt]]=id;
     64             V[cover[rt]].push_back(id);
     65         }
     66         return;
     67     }
     68     if(l==r) return;
     69     PushDown(rt);
     70     int m=mid;
     71     if(L<=m)
     72         query(L,R,id,lson);
     73     if(R>m)
     74         query(L,R,id,rson);
     75 }
     76 
     77 
     78 int main()
     79 {
     80     int t,n;
     81     scanf("%d",&t);
     82     while(t--)
     83     {
     84         scanf("%d",&n);
     85         memset(cover,-1,sizeof(cover));
     86         memset(hash,-1,sizeof(hash));
     87         for(int i=0;i<n;i++)
     88         {
     89             scanf("%d%d%d",&ss[i].s,&ss[i].t,&ss[i].x);
     90             ss[i].s<<=1;ss[i].t<<=1;V[i].clear();
     91         }
     92 
     93         sort(ss,ss+n,cmp);
     94 
     95         for(int i=0;i<n;i++)
     96         {
     97             query(ss[i].s,ss[i].t,i,0,MAXN<<1,1);
     98             update(ss[i].s,ss[i].t,i,0,MAXN<<1,1);
     99         }
    100         int ans=0;
    101         for(int i=0;i<n;i++)
    102         {
    103             for(int j=0;j<V[i].size();j++)
    104             {
    105                 int k=V[i][j];
    106                 for(int p=0;p<V[i].size();p++)
    107                     for(int q=0;q<V[k].size();q++)
    108                         if(V[i][p] == V[k][q])
    109                             ans++;
    110             }
    111         }
    112 
    113         printf("%d\n",ans);
    114     }
    115     return 0;
    116 }

     poj 1151(线段树+扫描线+离散化)

    题意:给你n个矩形的坐标 求矩形覆盖的总面积

     浮点数先要离散化;然后把矩形分成两条边,上边和下边,对横轴建树,然后从下到上扫描上去,用cnt表示该区间下边比上边多几个,sum代表该区间内被覆盖的线段的长度总和
    这里线段树的一个结点并非是线段的一个端点,而是该端点和下一个端点间的线段

     

    View Code
      1 //poj 1151 hdu 1542
      2 #include <iostream>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <algorithm>
      6 
      7 using namespace std;
      8 
      9 #define lson l,m,rt<<1
     10 #define rson m+1,r,rt<<1|1
     11 #define ls rt<<1
     12 #define rs rt<<1|1
     13 
     14 #define MAXN 220
     15 
     16 struct seg
     17 {
     18     double l,r,h;//l代表线段的左端点,r是右端点,h是该线段高,即y值
     19     int s;//s==1表示是矩形下边,s==-1是上边
     20     seg(){}
     21     seg(double a,double b,double c,int d):l(a),r(b),h(c),s(d){}
     22     bool operator < (const seg & a)const
     23     {
     24         return h<a.h;
     25     }
     26 }ss[MAXN];
     27 double X[MAXN],sum[MAXN<<2];
     28 int cnt[MAXN<<2];
     29 
     30 void PushUp(int rt,int l,int r)
     31 {
     32     if(cnt[rt])
     33         sum[rt]=X[r+1]-X[l];
     34     else if(l==r)
     35         sum[rt]=0;
     36     else
     37         sum[rt]=sum[ls]+sum[rs];
     38 }
     39 
     40 void update(int L,int R,int c,int l,int r,int rt)
     41 {
     42     if(L<=l && r<=R)
     43     {
     44         cnt[rt]+=c;
     45         PushUp(rt,l,r);
     46         return;
     47     }
     48 
     49     int m=(l+r)>>1;
     50     if(L<=m)
     51         update(L,R,c,lson);
     52     if(m<R)
     53         update(L,R,c,rson);
     54     PushUp(rt,l,r);
     55 }
     56 
     57 int Bin(double key,int n,double X[])
     58 {
     59     int l=0,r=n-1;
     60     while(l<=r)
     61     {
     62         int m=(l+r)>>1;
     63         if(X[m] == key ) return m;
     64         else if(X[m] <key)
     65             l=m+1;
     66         else
     67             r=m-1;
     68     }
     69     return -1;
     70 }
     71 
     72 int main()
     73 {
     74     int n;
     75     int set=1;
     76     while(scanf("%d",&n) && n)
     77     {
     78         double x1,x2,y1,y2;
     79         int m=0;
     80         for(int i=0;i<n;i++)
     81         {
     82             scanf("%lf%lf%lf%lf",&x1,&y1,&x2,&y2);
     83             X[m]=x1;
     84             ss[m++]=seg(x1,x2,y1,1);
     85             X[m]=x2;
     86             ss[m++]=seg(x1,x2,y2,-1);
     87         }
     88 
     89         sort(X,X+m);
     90         sort(ss,ss+m);
     91         
     92         int k=1;
     93         for(int i=1;i<m;i++)
     94             if(X[i] != X[i-1])
     95                 X[k++]=X[i];
     96         memset(cnt,0,sizeof(cnt));
     97         memset(sum,0,sizeof(sum));
     98         double ans=0;
     99 
    100         for(int i=0;i<m-1;i++)
    101         {
    102             int l=Bin(ss[i].l,k,X);
    103             int r=Bin(ss[i].r,k,X)-1;
    104 
    105             if(l<=r)
    106                 update(l,r,ss[i].s,0,k-1,1);
    107             ans+=sum[1]*(ss[i+1].h-ss[i].h);
    108         }
    109 
    110  
    111         printf("Test case #%d\nTotal explored area: %.2lf\n\n",set++,ans);
    112     }
    113     return 0;
    114 }

     

     

     

  • 相关阅读:
    攻防世界-web进阶-Web_php_include
    攻防世界-web进阶-php_rce
    Buuctf-misc-穿越时空的思念
    Buuctf-misc-[BJDCTF 2nd]EasyBaBa (kinovea)
    Buuctf-misc-菜刀666
    Buuctf-misc-[BJDCTF 2nd]圣火昭昭-y1ng(outguess)
    Access数据库简介
    VC与VB
    VB的使用
    工作总结2
  • 原文地址:https://www.cnblogs.com/Missa/p/2615907.html
Copyright © 2020-2023  润新知