线段树学习笔记

神牛传送门:

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 }

 

 

 

 

 

 

你可能感兴趣的:(学习笔记)