线段树 区间更新

poj3468 A Simple Problem with Integers

( m - ( m >> 1 ) )这里跪了几发。。 - 的优先级大于 >>

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<string>
 6 #include<queue>
 7 #include<cmath>
 8 #include<vector>
 9
10 using namespace std;
11
12 #define mnx 104000
13 #define ll long long
14 #define mod 1000000007
15 #define inf 0x3f3f3f3f
16 #define lson l, m, rt << 1
17 #define rson m+1, r, rt << 1 | 1
18
19 ll sum[mnx<<2], col[mnx<<2];
20 int n;
21 void pushup( int rt ){
22     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
23 }
24 void pushdown( int rt, int m ){
25     if( col[rt] ){
26         col[rt<<1] += col[rt];
27         col[rt<<1|1] += col[rt];
28         sum[rt<<1|1] += ( m >> 1 ) * col[rt] ;
29         sum[rt<<1] += ( m - ( m >> 1 ) ) * col[rt] ;
30         col[rt] = 0;
31     }
32 }
33 void build( int l, int r, int rt ){
34     col[rt] = 0;
35     if( l == r ){
36         scanf( "%I64d", &sum[rt] );
37         return;
38     }
39     int m = ( l + r ) >> 1;
40     build( lson );
41     build( rson );
42     pushup( rt );
43 }
44 void update( int L, int R, int v, int l, int r, int rt ){
45     if( L <= l && R >= r ){
46         sum[rt] += ( r - l + 1 ) * (ll)v;
47         col[rt] += v;
48         return ;
49     }
50     pushdown( rt, r - l + 1 );
51     int m = ( l + r ) >> 1;
52     if( L <= m ) update( L, R, v, lson );
53     if( R > m ) update( L, R, v, rson );
54     pushup( rt );
55 }
56 ll find( int L, int R, int l, int r, int rt ){
57     ll ret = 0;
58     if( L <= l && R >= r ){
59         return sum[rt];
60     }
61     pushdown( rt, r - l + 1 );
62     int m = ( l + r ) >> 1;
63     if( L <= m ) ret += find( L, R, lson );
64     if( R > m ) ret += find( L, R, rson );
65     //pushup( rt );
66     return ret;
67 }
68 int main(){
69     int q;
70     while( scanf( "%d %d", &n, &q ) != EOF ){
71         build( 1, n, 1 );
72         getchar();
73         while( q-- ){
74             char c;
75             int a, b, v;
76             cin >> c;
77             if( c == ‘Q‘ ){
78                 scanf( "%d %d", &a, &b );
79                 printf( "%I64d\n", find( a, b, 1, n, 1 ) );
80             }
81             else{
82                 scanf( "%d %d %d", &a, &b, &v );
83                 update( a, b, v, 1, n, 1 );
84             }
85         }
86     }
87     return 0;
88 }

poj2528 Mayor’s posters

题意:在墙上贴海报,海报可以互相覆盖,问最后可以看见几张海报
思路:这题数据范围很大,直接搞超时+超内存,需要离散化:
离散化简单的来说就是只取我们需要的值来用,比如说区间[1000,2000],[1990,2012] 我们用不到[-∞,999][1001,1989][1991,1999][2001,2011][2013,+∞]这些值,所以我只需要1000,1990,2000,2012就够了,将其分别映射到0,1,2,3,在于复杂度就大大的降下来了
所以离散化要保存所有需要用到的值,排序后,分别映射到1~n,这样复杂度就会小很多很多
而这题的难点在于每个数字其实表示的是一个单位长度(并非一个点),这样普通的离散化会造成许多错误(包括我以前的代码,poj这题数据奇弱)
给出下面两个简单的例子应该能体现普通离散化的缺陷:
例子一:1-10 1-4 5-10
例子二:1-10 1-4 6-10
普通离散化后都变成了[1,4][1,2][3,4]
线段2覆盖了[1,2],线段3覆盖了[3,4],那么线段1是否被完全覆盖掉了呢?
例子一是完全被覆盖掉了,而例子二没有被覆盖

为了解决这种缺陷,我们可以在排序后的数组上加些处理,比如说[1,2,6,10]
如果相邻数字间距大于1的话,在其中加上任意一个数字,比如加成[1,2,3,6,7,10],然后再做线段树就好了。。

 1 #include<iostream>
 2 #include<cstring>
 3 #include<algorithm>
 4 #include<cstdio>
 5 #include<string>
 6 #include<queue>
 7 #include<cmath>
 8 #include<vector>
 9
10 using namespace std;
11
12 #define mnx 10010
13 #define ll long long
14 #define mod 1000000007
15 #define inf 0x3f3f3f3f
16 #define lson l, m, rt << 1
17 #define rson m+1, r, rt << 1 | 1
18
19 int lx[mnx], rx[mnx], sum[mnx<<2], col[mnx<<4], n, ans;
20 bool vis[mnx<<2];
21 void pushdown( int rt ){
22     if( col[rt] ){
23         col[rt<<1] = col[rt<<1|1] = col[rt];
24         col[rt] = 0;
25     }
26 }
27 void update( int L, int R, int v, int l, int r, int rt ){
28     if( L <= l && R >= r ){
29         col[rt] = v;
30         return ;
31     }
32     pushdown( rt );
33     int m = ( l + r ) >> 1;
34     if( L <= m ) update( L, R, v, lson );
35     if( R > m ) update( L, R, v, rson );
36 }
37
38 int bin_search( int goal, int n ){
39     int l = 0, r = n - 1;
40     while( l < r ){
41         int m = ( l + r ) >> 1;
42         if( sum[m] < goal ){
43             l = m + 1;
44         }
45         else r = m;
46     }
47     return l;
48 }
49 void find( int l, int r, int rt ){
50     if( l == r ){
51         if( col[rt] == 0 ) return ;
52         if( !vis[col[rt]] ) ans++;
53         vis[col[rt]] = 1;
54         return ;
55     }
56     pushdown( rt );
57     int m = ( l + r ) >> 1;
58     find( lson );
59     find( rson );
60 }
61 int main(){
62     int cas;
63     scanf( "%d", &cas );
64     while( cas-- ){
65         memset( col, 0, sizeof(col) );
66         memset( vis, 0, sizeof(vis) );
67         int cnt = 0;
68         scanf( "%d", &n );
69         for( int i = 0; i < n; i++ ){
70             scanf( "%d %d", &lx[i], &rx[i] );
71             sum[cnt++] = lx[i];
72             sum[cnt++] = rx[i];
73         }
74         sort( sum, sum + cnt );
75         cnt = unique( sum, sum + cnt ) - sum;
76         int kk = cnt;
77         for( int i = 1; i < cnt; i++ ){
78             if( sum[i] - sum[i-1] != 1 ){
79                 sum[kk++] = sum[i-1] + 1;
80             }
81         }
82         sort( sum, sum + kk );
83         for( int i = 0; i < n; i++ ){
84             int l = bin_search( lx[i], kk ) + 1;
85             int r = bin_search( rx[i], kk ) + 1;
86             //cout<<l<<" "<<r<<endl;
87             update( l, r, i+1, 1, kk, 1 );
88         }
89         ans = 0;
90         find( 1, kk, 1 );
91         printf( "%d\n", ans );
92     }
93     return 0;
94 }

poj3225 Help with Intervals

做的好恶心啊,只好边看代码边做。。
题意:区间操作,交,并,补等
思路:
我们一个一个操作来分析:(用0和1表示是否包含区间,-1表示该区间内既有包含又有不包含)
U:把区间[l,r]覆盖成1
I:把[-∞,l)(r,∞]覆盖成0
D:把区间[l,r]覆盖成0
C:把[-∞,l)(r,∞]覆盖成0 , 且[l,r]区间0/1互换
S:[l,r]区间0/1互换

成段覆盖的操作很简单,比较特殊的就是区间0/1互换这个操作,我们可以称之为异或操作
很明显我们可以知道这个性质:当一个区间被覆盖后,不管之前有没有异或标记都没有意义了
所以当一个节点得到覆盖标记时把异或标记清空
而当一个节点得到异或标记的时候,先判断覆盖标记,如果是0或1,直接改变一下覆盖标记,不然的话改变异或标记

开区间闭区间只要数字乘以2就可以处理(偶数表示端点,奇数表示两端点间的区间)
线段树功能:update:成段替换,区间异或 query:简单hash

  1 #include<iostream>
  2 #include<cstring>
  3 #include<algorithm>
  4 #include<cstdio>
  5 #include<string>
  6 #include<queue>
  7 #include<cmath>
  8 #include<vector>
  9
 10 using namespace std;
 11
 12 #define mnx 131072
 13 #define ll long long
 14 #define mod 1000000007
 15 #define inf 0x3f3f3f3f
 16 #define lson l, m, rt << 1
 17 #define rson m+1, r, rt << 1 | 1
 18
 19 const int n = 131072;
 20 int cover[mnx<<2], Xor[mnx<<2];
 21 bool vis[mnx+1];
 22 void Fxor( int rt ){
 23     if( cover[rt] != -1 ) cover[rt] ^= 1;
 24     else Xor[rt] ^= 1;
 25 }
 26 void pushdown( int rt ){
 27     if( cover[rt] != -1 ){
 28         cover[rt<<1] = cover[rt<<1|1] = cover[rt];
 29         Xor[rt<<1] = Xor[rt<<1|1] = 0;
 30         cover[rt] = -1;
 31     }
 32     if( Xor[rt] ){
 33         Fxor( rt<<1 );
 34         Fxor( rt<<1|1 );
 35         Xor[rt] = 0;
 36     }
 37 }
 38 void update( int L, int R, char c, int l, int r, int rt ){
 39     if( L <= l && R >= r ){
 40         if( c == ‘U‘ ){
 41             cover[rt] = 1;
 42             Xor[rt] = 0;
 43         }
 44         else if( c == ‘D‘ ){
 45             cover[rt] = 0;
 46             Xor[rt] = 0;
 47         }
 48         else if( c == ‘S‘ || c == ‘C‘ ){
 49             Fxor( rt );
 50         }
 51         return ;
 52     }
 53     pushdown( rt );
 54     int m = ( l + r ) >> 1;
 55     if( L <= m ) update( L, R, c, lson );
 56     else if( c == ‘C‘ || c == ‘I‘ ){
 57         cover[rt<<1] = Xor[rt<<1] = 0;
 58     }
 59     if( R > m ) update( L, R, c, rson );
 60     else if( c == ‘C‘ || c == ‘I‘ ){
 61         cover[rt<<1|1] = Xor[rt<<1|1] = 0;
 62     }
 63 }
 64 void find( int l, int r, int rt ){
 65     if( cover[rt] == 1 ){
 66         for( int i = l; i <= r; i++ ){
 67             vis[i] = 1;
 68         }
 69         return ;
 70     }
 71     if( cover[rt] == 0 ) return;
 72     pushdown( rt );
 73     int m = ( l + r ) >> 1;
 74     find( lson );
 75     find( rson );
 76 }
 77 int main(){
 78     char op, a, b;
 79     int l, r;
 80     while( scanf( "%c %c%d,%d%c\n", &op, &a, &l, &r, &b ) != EOF ){
 81         l <<= 1, r <<= 1;
 82         if( a == ‘(‘ ) l++;
 83         if( b == ‘)‘ ) r--;
 84         if( l > r ){
 85             if( op == ‘C‘ || op == ‘I‘ ){
 86                 cover[1] = Xor[1] = 0;
 87             }
 88         }
 89         else update( l, r, op, 0, n, 1 );
 90     }
 91     find( 0, n, 1 );
 92     l = -1;
 93     bool flag = 0;
 94     for( int i = 0; i < n; i++ ){
 95         if( vis[i] ){
 96             if( l == -1 ){
 97                 l = i;
 98             }
 99             r = i;
100         }
101         else{
102             if( l == -1 ) continue;
103             if( flag ) printf( " " );
104             flag = 1;
105             printf( "%c%d,%d%c", l&1 ? ‘(‘ : ‘[‘, l>>1, (r+1)>>1, r&1 ? ‘)‘ : ‘]‘ );
106             l = -1;
107         }
108     }
109     if( !flag ) printf( "empty set" );
110     printf( "\n" );
111     return 0;
112 }

线段树 区间更新,布布扣,bubuko.com

时间: 2024-11-05 04:48:58

线段树 区间更新的相关文章

HDU 1689 Just a Hook 线段树区间更新求和

点击打开链接 Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 18894    Accepted Submission(s): 9483 Problem Description In the game of DotA, Pudge's meat hook is actually the most horrible

POJ 2528 Mayor&#39;s posters (线段树区间更新+离散化)

题目链接:http://poj.org/problem?id=2528 给你n块木板,每块木板有起始和终点,按顺序放置,问最终能看到几块木板. 很明显的线段树区间更新问题,每次放置木板就更新区间里的值.由于l和r范围比较大,内存就不够了,所以就用离散化的技巧 比如将1 4化为1 2,范围缩小,但是不影响答案. 写了这题之后对区间更新的理解有点加深了,重点在覆盖的理解(更新左右两个孩子节点,然后值清空),还是要多做做题目. 1 #include <iostream> 2 #include <

Hdu 3966 Aragorn&#39;s Story (树链剖分 + 线段树区间更新)

题目链接: Hdu 3966 Aragorn's Story 题目描述: 给出一个树,每个节点都有一个权值,有三种操作: 1:( I, i, j, x ) 从i到j的路径上经过的节点全部都加上x: 2:( D, i, j, x ) 从i到j的路径上经过的节点全部都减去x: 3:(Q, x) 查询节点x的权值为多少? 解题思路: 可以用树链剖分对节点进行hash,然后用线段树维护(修改,查询),数据范围比较大,要对线段树进行区间更新 1 #include <cstdio> 2 #include

HDU 5023 A Corrupt Mayor&#39;s Performance Art 线段树区间更新+状态压缩

Link:  http://acm.hdu.edu.cn/showproblem.php?pid=5023 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 #include <vector> 6 #include <string> 7 #include <cmath> 8 using namesp

hihocoder 1080 线段树(区间更新)

题目链接:http://hihocoder.com/problemset/problem/1080 , 两种操作的线段树(区间更新). 这道题前一段时间一直卡着我,当时也是基础不扎实做不出来,今天又想了想其实还是比较简单的,也只能怪自己太弱了. 这道题坑就坑在是有两个操作:set和add,所以lazy标记数组就需要两个,但是有一点要考虑的是一个区间上set与add的先后关系——如果对于一个区间set和add标记同时存在,那么应该如果处理:一种情况set在add之前,那么就按照正常顺序来就可以了:

(简单) POJ 3468 A Simple Problem with Integers , 线段树+区间更新。

Description You have N integers, A1, A2, ... , AN. You need to deal with two kinds of operations. One type of operation is to add some given number to each number in a given interval. The other is to ask for the sum of numbers in a given interval. 题意

HDU 5023 A Corrupt Mayor&#39;s Performance Art(线段树区间更新)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5023 解题报告:一面墙长度为n,有N个单元,每个单元编号从1到n,墙的初始的颜色是2,一共有30种颜色,有两种操作: P a b c  把区间a到b涂成c颜色 Q a b 查询区间a到b的颜色 线段树区间更新,每个节点保存的信息有,存储颜色的c,30种颜色可以压缩到一个int型里面存储,然后还有一个tot,表示这个区间一共有多少种颜色. 对于P操作,依次往下寻找,找要更新的区间,找到要更新的区间之前

POJ 2777 Count Color (线段树区间更新加查询)

Description Chosen Problem Solving and Program design as an optional course, you are required to solve all kinds of problems. Here, we get a new problem. There is a very long board with length L centimeter, L is a positive integer, so we can evenly d

HDU 4902 Nice boat(线段树 区间更新)

Nice boat 大意:给你一个区间,每次可以进行两种操作,1:把区间中的数全都变成x  2:把区间中大于x的数变成gcd(a[i], x),最后输出序列. 思路:线段树成段更行,用num数组的叶子存储数据,节点当作lazy来使用. 1 #include <stdio.h> 2 const int maxn = 100005; 3 4 int num[maxn<<2]; 5 6 int gcd(int a, int b){ 7 return b?gcd(b, a%b):a; 8

线段树区间更新

区间更新也可以分割成若干个子区间, 每层的结点至多选取 2 个,时间复杂度 O(logn). 懒惰(Lazy)标记 懒惰标记,也可称为延迟标记.一个区间可以转化为若干个结点,每个结点设一个标记,记录这个结点被进行了某种修改操作(这种修改操作会影响其子结点). 也就是说,仅修改到这些结点,暂不修改其子结点:而后决定访问其子节点时,再下传懒惰 (Lazy) 标记,并消除原来的标记. 优点在于,不用将区间的所有值暴力更新,大大提高效率. 在区间修改的一类问题中,我们可以设一个 delta 域,表示该节