zoukankan      html  css  js  c++  java
  • 线段树

    线段树 详解请看大佬博客:http://www.cnblogs.com/TheRoadToTheGold/p/6254255.html

    几个模板题:

     1.洛谷 P3372 【模板】线段树 1

    题目描述

    如题,已知一个数列,你需要进行下面两种操作:

    1.将某区间每一个数加上x

    2.求出某区间每一个数的和

    输入输出格式

    输入格式:

    第一行包含两个整数N、M,分别表示该数列数字的个数和操作的总个数。

    第二行包含N个用空格分隔的整数,其中第i个数字表示数列第i项的初始值。

    接下来M行每行包含3或4个整数,表示一个操作,具体如下:

    操作1: 格式:1 x y k 含义:将区间[x,y]内每个数加上k

    操作2: 格式:2 x y 含义:输出区间[x,y]内每个数的和

    输出格式:

    输出包含若干行整数,即为所有操作2的结果。

    输入输出样例

    输入样例#1:
    5 5
    1 5 4 2 3
    2 2 4
    1 2 3 2
    2 3 4
    1 1 5 1
    2 1 4
    输出样例#1:
    11
    8
    20

    说明

    时空限制:1000ms,128M

    数据规模:

    对于30%的数据:N<=8,M<=10

    对于70%的数据:N<=1000,M<=10000

    对于100%的数据:N<=100000,M<=100000

    (数据已经过加强^_^,保证在int64/long long数据范围内)

    样例说明:

    思路:

      纯模板题,数据范围有提示在long long范围内,注意ans一定要清0!!!

      cin全都MLE,改成scanf就欧了。

    (⊙v⊙)嗯~ 代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 typedef long long LL;
     6 const LL N = 1e9;
     7 LL n,m,a,b,c,d,ans;
     8 
     9 struct Tree{
    10     LL x,y,w,f;
    11 }tree[400001];
    12 
    13 void build(LL k,LL l,LL r) {
    14     tree[k].x = l,tree[k].y = r;
    15     if(l == r) {
    16 //        cin>>tree[k].w;
    17         scanf("%lld",&tree[k].w);
    18         return ;
    19     }
    20     LL mid = (l + r)/2;
    21     build(k*2,l,mid);
    22     build(k*2+1,mid+1,r);
    23     tree[k].w=tree[k*2].w + tree[k*2+1].w;
    24 }
    25 
    26 void down(int k) {
    27     tree[k*2].f+=tree[k].f;
    28     tree[k*2+1].f+=tree[k].f;
    29     tree[k*2].w+=tree[k].f * (tree[k*2].y - tree[k*2].x + 1);
    30     tree[k*2+1].w+=(tree[k*2+1].y - tree[k*2+1].x +1) * tree[k].f;
    31     tree[k].f = 0;
    32 }
    33 
    34 void Change(int k) {
    35     if(tree[k].x>=a&&tree[k].y<=b){
    36         tree[k].w+=(tree[k].y-tree[k].x+1)*d;
    37         tree[k].f+=d;
    38         return ;
    39     }
    40     if(tree[k].f) down(k);
    41     int mid = (tree[k].x + tree[k].y)/2;
    42     if(a<=mid) Change(k*2);
    43     if(b>mid) Change(k*2+1);
    44     tree[k].w = tree[k*2].w + tree[k*2+1].w;
    45 }
    46 
    47 void Ask(int k) {
    48     if(tree[k].x>=a && tree[k].y<=b) {
    49         ans += tree[k].w ;
    50         return ;
    51     }
    52     if(tree[k].f) down(k);
    53     int mid = (tree[k].x + tree[k].y)/2;
    54     if(a<=mid) Ask(k*2);
    55     if(b>mid) Ask(k*2+1);
    56 }
    57 
    58 int main() {
    59     cin>>n>>m;
    60     build(1,1,n);
    61     for(LL i=1; i<=m; i++) {
    62 //        cin>>c;
    63         scanf("%lld",&c);
    64         if(c == 1) {
    65 //            cin>>a>>b>>d;
    66             scanf("%lld%lld%lld",&a,&b,&d);
    67             Change(1);
    68         }
    69         if(c == 2) {
    70 //            cin>>a>>b;
    71             scanf("%lld%lld",&a,&b);
    72             ans=0,Ask(1);
    73 //            cout<<ans<<endl;
    74             printf("%lld
    ",ans);
    75         }
    76     }
    77     return 0;
    78 } 

    2.Codevs 1080 线段树练习

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 钻石 Diamond
    题目描述 Description

    一行N个方格,开始每个格子里都有一个整数。现在动态地提出一些问题和修改:提问的形式是求某一个特定的子区间[a,b]中所有元素的和;修改的规则是指定某一个格子x,加上或者减去一个特定的值A。现在要求你能对每个提问作出正确的回答。1≤N<100000,,提问和修改的总数m<10000条。

    输入描述 Input Description

    输入文件第一行为一个整数N,接下来是n行n个整数,表示格子中原来的整数。接下一个正整数m,再接下来有m行,表示m个询问,第一个整数表示询问代号,询问代号1表示增加,后面的两个数x和A表示给位置X上的数值增加A,询问代号2表示区间求和,后面两个整数表示a和b,表示要求[a,b]之间的区间和。

    输出描述 Output Description

    共m行,每个整数

    样例输入 Sample Input

    6

    3

    4

    1 3 5

    2 1 4

    1 1 9

    2 2 6

    样例输出 Sample Output

    22

    22

    数据范围及提示 Data Size & Hint

    1≤N≤100000, m≤10000 。

    分类标签 Tags 点此展开 

    思路:
      纯模板题。。。
    (⊙v⊙)嗯~ 代码:
     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 typedef long long LL;
     6 const int N = 400001;
     7 int n,m,p;
     8 struct Tree{
     9     int l,r,w,f;
    10 }tree[N];
    11 LL a,b,ch,ans,typ;
    12 
    13 void build(int k,int ll,int rr){
    14     tree[k].l = ll,tree[k].r = rr;
    15     if(tree[k].l==tree[k].r) {
    16         scanf("%lld",&tree[k].w);
    17         return ;
    18     }
    19     int mid=(ll+rr)/2;
    20     build(k*2,ll,mid);
    21     build(k*2+1,mid+1,rr);
    22     tree[k].w = tree[k*2].w + tree[k*2+1].w ;
    23 }
    24 
    25 void down(int k) { //懒标记 
    26     tree[k*2].f += tree[k].f ;
    27     tree[k*2+1].f += tree[k].f ;
    28     tree[k*2].w += tree[k].f * (tree[k*2].l - tree[k*2].r + 1);
    29     tree[k*2+1].w += tree[k].f * (tree[k*2+1].l -tree[k*2+1].r +1);
    30     tree[k].f = 0;
    31 }
    32 
    33 void Ask(int k){//区间询问 
    34     if(tree[k].l>=a&&tree[k].r<=b){
    35         ans+=tree[k].w;
    36         return ;
    37     }
    38     if(tree[k].f) down(k);
    39     int mid = (tree[k].r + tree[k].l)/2;
    40     if(a<=mid) Ask(k*2);
    41     if(b>mid) Ask(k*2+1);
    42 }
    43 
    44 void Change_only(int k){
    45     if(tree[k].l==tree[k].r) {
    46         tree[k].w += ch;
    47         return ;
    48     }
    49     int mid = (tree[k].r + tree[k].l)/2;
    50     if(a<=mid) Change_only(k*2);
    51     else Change_only(k*2+1);
    52     tree[k].w = tree[k*2].w + tree[k*2+1].w ;
    53 }
    54 
    55 int main() {
    56     cin>>n;
    57     build(1,1,n);
    58     cin>>m;
    59     while(m--){
    60         cin>>typ;
    61         if(typ==1) {
    62             scanf("%lld%lld",&a,&ch);
    63             Change_only(1);
    64         }
    65         if(typ==2){
    66             scanf("%lld%lld",&a,&b);
    67             ans=0;
    68             Ask(1);
    69             cout<<ans<<endl;
    70         }
    71     }
    72     return 0;
    73 }

    3.Codevs 1081 线段树练习 2

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 大师 Master
    题目描述 Description

    给你N个数,有两种操作

    1:给区间[a,b]的所有数都增加X

    2:询问第i个数是什么?

    输入描述 Input Description

    第一行一个正整数n,接下来n行n个整数,再接下来一个正整数Q,表示操作的个数. 接下来Q行每行若干个整数。如果第一个数是1,后接3个正整数a,b,X,表示在区间[a,b]内每个数增加X,如果是2,后面跟1个整数i, 表示询问第i个位置的数是多少。

    输出描述 Output Description

    对于每个询问输出一行一个答案

    样例输入 Sample Input

    3

    1

    2

    3

    2

    1 2 3 2

    2 3

    样例输出 Sample Output

    5

    数据范围及提示 Data Size & Hint

    数据范围

    1<=n<=100000

    1<=q<=100000

    分类标签 Tags 点此展开 

    思路:
      纯模板题。。。
    (⊙v⊙)嗯~ 代码:
     1 #include<iostream>
     2 #include<cstdio>
     3 using namespace std;
     4 
     5 typedef long long LL;
     6 const int N = 400001;
     7 int n,m,p;
     8 struct Tree{
     9     int l,r,w,f;
    10 }tree[N];
    11 LL a,b,ch,ans,typ;
    12 
    13 void build(int k,int ll,int rr){
    14     tree[k].l = ll,tree[k].r = rr;
    15     if(tree[k].l==tree[k].r) {
    16         scanf("%lld",&tree[k].w);
    17         return ;
    18     }
    19     int mid=(ll+rr)/2;
    20     build(k*2,ll,mid);
    21     build(k*2+1,mid+1,rr);
    22     tree[k].w = tree[k*2].w + tree[k*2+1].w ;
    23 }
    24 
    25 void down(int k) { //懒标记 
    26     tree[k*2].f += tree[k].f ;
    27     tree[k*2+1].f += tree[k].f ;
    28     tree[k*2].w += tree[k].f * (tree[k*2].l - tree[k*2].r + 1);
    29     tree[k*2+1].w += tree[k].f * (tree[k*2+1].l -tree[k*2+1].r +1);
    30     tree[k].f = 0;
    31 }
    32 
    33 void Change(int k){//区间修改 
    34     if(tree[k].l>=a&&tree[k].r<=b) {
    35         tree[k].w += (tree[k].r - tree[k].l + 1) * ch;
    36         tree[k].f += ch;
    37         return ;
    38     }
    39     if(tree[k].f) down(k);
    40     int mid = (tree[k].r + tree[k].l)/2;
    41     if(a<=mid) Change(k*2);
    42     if(b>mid) Change(k*2+1);
    43     tree[k].w = tree[k*2].w + tree[k*2+1].w ;
    44 }
    45 
    46 void Ask_only(int k) {
    47     if(tree[k].l==tree[k].r){
    48         ans=tree[k].w;
    49         return ;
    50     }
    51     if(tree[k].f) down(k);
    52     int mid = (tree[k].r + tree[k].l)/2;
    53     if(a<=mid) Ask_only(k*2);
    54     else Ask_only(k*2+1);
    55 }
    56 
    57 int main() {
    58     cin>>n;
    59     build(1,1,n);
    60     cin>>m;
    61     while(m--){
    62         cin>>typ;
    63         if(typ==1) {
    64             scanf("%lld%lld%lld",&a,&b,&ch);
    65             Change(1);
    66         }
    67         if(typ==2){
    68             scanf("%lld",&a);
    69             Ask_only(1);
    70             cout<<ans<<endl;
    71         }
    72     }
    73     return 0;
    74 }

    4.Codevs 1082 线段树练习 3

     时间限制: 3 s
     空间限制: 128000 KB
     题目等级 : 大师 Master
    题目描述 Description

    给你N个数,有两种操作:

    1:给区间[a,b]的所有数增加X

    2:询问区间[a,b]的数的和。

    输入描述 Input Description

    第一行一个正整数n,接下来n行n个整数,

    再接下来一个正整数Q,每行表示操作的个数,

    如果第一个数是1,后接3个正整数,

    表示在区间[a,b]内每个数增加X,如果是2,

    表示操作2询问区间[a,b]的和是多少。

    pascal选手请不要使用readln读入

    输出描述 Output Description

    对于每个询问输出一行一个答案

    样例输入 Sample Input

    3

    1

    2

    3

    2

    1 2 3 2

    2 2 3

    样例输出 Sample Output

    9

    数据范围及提示 Data Size & Hint

    数据范围

    1<=n<=200000

    1<=q<=200000

    分类标签 Tags 点此展开 

    思路:
      纯模板题。。。
    (⊙v⊙)嗯~ 代码:
     1 #include<cstdio>
     2 using namespace std;
     3 
     4 const int N = 900001;
     5 int n,m,a,b,ch,typ;;
     6 struct Tree{
     7     long long l,r,w,f;
     8 }tree[N];
     9 long long ans;
    10 
    11 void build(int k,int ll,int rr){
    12     tree[k].l = ll,tree[k].r = rr;
    13     if(tree[k].l==tree[k].r) {
    14         scanf("%d",&tree[k].w);
    15         return ;
    16     }
    17     int mid=(ll+rr)/2;
    18     build(k*2,ll,mid);
    19     build(k*2+1,mid+1,rr);
    20     tree[k].w = tree[k*2].w + tree[k*2+1].w ;
    21 }
    22 
    23 void down(int k) { //懒标记 
    24     tree[k*2].f += tree[k].f ;
    25     tree[k*2+1].f += tree[k].f ;
    26     tree[k*2].w += tree[k].f * (tree[k*2].r - tree[k*2].l + 1);
    27     tree[k*2+1].w += tree[k].f * (tree[k*2+1].r -tree[k*2+1].l +1);
    28     tree[k].f = 0;
    29 }
    30 
    31 void Ask(int k){//区间询问 
    32     if(tree[k].l>=a&&tree[k].r<=b){
    33         ans+=tree[k].w;
    34         return ;
    35     }
    36     if(tree[k].f) down(k);
    37     int mid = (tree[k].r + tree[k].l)/2;
    38     if(a<=mid) Ask(k*2);
    39     if(b>mid) Ask(k*2+1);
    40 }
    41 
    42 void Change(int k){//区间修改 
    43     if(tree[k].l>=a&&tree[k].r<=b) {
    44         tree[k].w += (tree[k].r - tree[k].l + 1) * ch;
    45         tree[k].f += ch;
    46         return ;
    47     }
    48     if(tree[k].f) down(k);
    49     int mid = (tree[k].r + tree[k].l)/2;
    50     if(a<=mid) Change(k*2);
    51     if(b>mid) Change(k*2+1);
    52     tree[k].w = tree[k*2].w + tree[k*2+1].w ;
    53 }
    54 
    55 int main() {
    56     scanf("%d",&n);
    57     build(1,1,n);
    58     scanf("%d",&m);
    59     while(m--){
    60         scanf("%d",&typ);
    61         ans=0;
    62         if(typ==1) {
    63             scanf("%d%d%d",&a,&b,&ch);
    64             Change(1);
    65         }
    66         if(typ==2){
    67             scanf("%d%d",&a,&b);
    68             Ask(1);
    69             printf("%lld
    ",ans);
    70         }
    71     }
    72     return 0;
    73 }

    自己选的路,跪着也要走完!!!

  • 相关阅读:
    Java hibernate 遇到的问题:could not read a hi value
    Java 小知识
    Java 在使用@Select遇到的问题:拼接字符串将数组拼为了字符串
    飞逝的光阴
    终于回来了
    再说创客
    离开一段时间
    抛弃QP
    关于创客
    对DTU系统结构的重新思考
  • 原文地址:https://www.cnblogs.com/wsdestdq/p/6832960.html
Copyright © 2011-2022 走看看