poj 2892 && 3468

     虽然训练计划里这两道题目不是归为线段树的,但是觉得这几道题目都是可以用线段树解决的。

题目:http://poj.org/problem?id=3468

题意:给你N个数,下面是两种操作 a b c是说把从a 到 b 的数全部加上 c ,Q a b 是说询问 从a 到 b的和

思路:线段树的成段更新,线段树中节点除了区间端点外和保存区间和以外,加一个记录权重的,也就是当一段被加上一个数时,这段的权重进行修改,根据权重和原先记录的和求得修改以后的和

View Code
 1 #include <iostream>
 2 #include <stdio.h>
 3 #include <string.h>
 4 #define N 100010
 5 
 6 using namespace std;
 7 
 8 typedef long long ll;
 9 struct node
10 {
11     int l, r;
12     ll s, d;  // d 保存每段修改的数 c ,s 用来记录区间和
13 }tr[N * 3];
14 int val[N];
15 void build(int s,int e,int d)
16 {
17     tr[d].l = s;
18     tr[d].r = e;
19     tr[d].d = 0;
20     if( s == e)
21     {
22         tr[d].s = val[s];
23         return ;
24     }
25     int mid = (s + e) / 2;
26     build(s,mid,d * 2);
27     build(mid + 1,e,d * 2 + 1);
28     tr[d].s = tr[d * 2].s + tr[d * 2 + 1].s;
29 }
30 void insert(int s,int e,int d,int v)
31 {
32     if(s == tr[d].l && e == tr[d].r)
33     {
34         tr[d].d += v;  // 更新权重
35         return ;
36     }
37     int mid = (tr[d].l + tr[d].r) / 2;
38     if(e <= mid) insert(s,e,d * 2,v);
39     else if(s > mid) insert(s,e,d * 2 + 1,v);
40     else
41     {
42         insert(s,mid,d * 2,v);
43         insert(mid + 1,e,d * 2 + 1,v);
44     }
45     // 计算修改的值
46     int ans1 = tr[d * 2].d * (tr[d * 2].r - tr[d * 2].l + 1);
47     int ans2 = tr[d * 2 + 1].d * (tr[d * 2 + 1].r - tr[d * 2 + 1].l + 1);
48     int ans3 = tr[d * 2].s + tr[d * 2 + 1].s;
49     tr[d].s = ans1 + ans2 + ans3;
50 }
51 ll quey(int s,int e,int d)
52 {
53     if(tr[d].l == s && tr[d].r == e)
54     {
55         return tr[d].s + tr[d].d * (e - s + 1);
56     }
57     ll sum;
58     int mid = (tr[d].l + tr[d].r) / 2;
59     if(e <= mid) sum = quey(s,e,d * 2);
60     else if(s > mid) sum = quey(s,e,d * 2 + 1);
61     else sum = quey(s,mid,d * 2) + quey(mid + 1,e,d * 2 + 1);
62     return sum + tr[d].d * (e - s + 1);
63 }
64 int main()
65 {
66     int i,n,m;
67     int x,y,z;
68     char str[2];
69     freopen("data.txt","r",stdin);
70     while(scanf("%d%d", &n, &m) != EOF)
71     {
72         for(i = 1; i <= n; i++) scanf("%d", &val[i]);
73         build(1,n,1);
74         while(m--)
75         {
76             scanf("%s",str);
77             if(str[0] == 'C')
78             {
79                 scanf("%d%d%d",&x,&y,&z);
80                 insert(x,y,1,z);
81             }
82             else
83             {
84                 scanf("%d%d",&x,&y);
85                 printf("%lld\n", quey(x,y,1));
86             }
87         }
88     }
89     return 0;
90 }

题目:http://poj.org/problem?id=2892

题意:首先给出N个联通的城堡,D x 表示第 x 个城堡被摧毁,Q x 表示询问包括 x 在内的城堡最长连续没被摧毁的城堡个数,R表示修复最后一个被摧毁的城堡(如果有连续的 R  然后是倒数第二个,倒数第三个 ~~~~)

这个题目数据可能弱了,用暴力也能过,就是开两个数组,一个记录城堡的好坏,一个记录城堡被摧毁的顺序

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #define N 50010
 6 #define _clr(a,val) (memset(a,val,sizeof(a)))
 7 
 8 using namespace std;
 9 
10 int stack[N];
11 int good[N];
12 int main()
13 {
14     int i,x;
15     int n,m;
16     char str[2];
17     //freopen("data.txt","r",stdin);
18     while(scanf("%d%d",&n,&m) != EOF)
19     {
20         _clr(stack,0);
21         _clr(good,0);
22         int num = 0;
23         while(m--)
24         {
25             scanf("%s",str);
26             if(str[0] == 'D')
27             {
28                 scanf("%d",&x);
29                 good[x] = 1;
30                 stack[num++] = x;
31             }
32             else if(str[0] == 'R')
33             {
34                 scanf("%d",&x);
35                 good[stack[--num]] = 0;
36             }
37             else
38             {
39                 int ans = 1;
40                 scanf("%d",&x);
41                 if(good[x] == 1)
42                 {
43                     printf("0\n");
44                     continue;
45                 }
46                 for(i = x + 1; i <= n; i++)
47                 {
48                     if(good[i] == 0) ans++;
49                     else break;
50                 }
51                 for(i = x - 1; i >= 1; i--)
52                 {
53                     if(good[i] == 0) ans++;
54                     else break;
55                 }
56                 printf("%d\n",ans);
57             }
58         }
59     }
60     return 0;
61 }

还有就是用线段树,具体注释看代码吧

View Code
 1 #include <stdio.h>
 2 #include <string.h>
 3 #include <iostream>
 4 #include <algorithm>
 5 #define N 50010
 6 #define _clr(a,val) (memset(a,val,sizeof(a)))
 7 
 8 using namespace std;
 9 struct node
10 {
11     int lmax;  // 保存该区间从左端点起最长连续的城堡数(没有被摧毁的)
12     int rmax;  // 保存该区间到右端点结束的最长连续城堡数
13     int val;   // 记录城堡是否被摧毁,1代表被摧毁,0代表完好
14 }tr[N * 4];
15 int stack[N];
16 void build(int s,int e,int d)
17 {
18     tr[d].lmax = tr[d].rmax = e - s + 1;
19     if(s == e) return;
20     int mid = (s + e) / 2;
21     build(s,mid,d * 2);
22     build(mid + 1,e,d * 2 + 1);
23 }
24 void insert(int s,int e,int d,int x,int val)
25 {
26     if(s == e)
27     {
28         tr[d].val = val;
29         if(val) tr[d].lmax = tr[d].rmax = 0;
30         else tr[d].lmax = tr[d].rmax = 1;
31         return ;
32     }
33     int mid = (s + e) / 2;
34     int l = d * 2;
35     int r = d * 2 + 1;
36     if(x <= mid) insert(s,mid,l,x,val);
37     else insert(mid + 1,e,r,x,val);
38     if(tr[l].lmax == mid - s + 1) tr[d].lmax = tr[r].lmax + tr[l].rmax;  // 如果左孩子中没有被摧毁的城堡,那么当前区间的 lmax 就是 左 + 右
39     else tr[d].lmax = tr[l].lmax;   // 否则就直接等于 左
40     if(tr[r].rmax == e - mid) tr[d].rmax = tr[r].rmax + tr[l].rmax;  // 该区间的 rmax 计算如上
41     else tr[d].rmax = tr[r].rmax;
42 }
43 int quey(int s,int e,int d,int x)
44 {
45     if(e == s)
46     {
47         if(tr[d].val == 0) return 1;
48         else return 0;
49     }
50     int mid = (s + e) / 2;
51     int l = d * 2;
52     int r = d * 2 + 1;
53     if(x <= mid) // 询问点在左孩子的情况
54     {
55         if(x > mid - tr[l].rmax) return tr[l].rmax + tr[r].lmax; // 如果询问的点在 以左孩子右端点为终点的最长连续城堡 的范围内,那么所求答案就是左孩子的 rmax + 右孩子的 lmax
56         else return quey(s,mid,l,x);  // 如果不在上诉范围内,那么就递归访问左孩子,继续查找
57     }
58     else  // 询问点在右孩子的情况  计算方法同左孩子
59     { 
60         if(x <= mid + tr[r].lmax) return tr[l].rmax + tr[r].lmax;
61         else return quey(mid + 1,e,r,x);
62     }
63 }
64 int main()
65 {
66     int x;
67     int n,m;
68     char str[2];
69     //freopen("data.txt","r",stdin);
70     while(scanf("%d%d",&n,&m) != EOF)
71     {
72         _clr(stack,0);
73         build(1,n,1);
74         int num = 0;
75         while(m--)
76         {
77             scanf("%s",str);
78             if(str[0] == 'D')
79             {
80                 scanf("%d",&x);
81                 stack[num ++] = x;
82                 insert(1,n,1,x,1);
83             }
84             else if(str[0] == 'R')
85             {
86                 insert(1,n,1,stack[-- num],0);
87             }
88             else
89             {
90                 scanf("%d",&x);
91                 printf("%d\n",quey(1,n,1,x));
92             }
93         }
94     }
95     return 0;
96 }
原文地址:https://www.cnblogs.com/fxh19911107/p/2625112.html