zoukankan      html  css  js  c++  java
  • 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 }
  • 相关阅读:
    Maven入门教程
    认识Java Core和Heap Dump
    [Java IO]03_字符流
    Eclipse 实用技巧
    可变和不可变的区分
    什么猴子补丁待补充
    当退出python时,是否释放全部内存
    解释python中的help()和dir()函数
    在python中是如何管理内存的
    解释一下python中的继承
  • 原文地址:https://www.cnblogs.com/fxh19911107/p/2625112.html
Copyright © 2011-2022 走看看