• 线段树 区间更新


    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
    ", 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 }
    View Code

    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
    ", ans );
    92     }
    93     return 0;
    94 }
    View Code

    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
    ", &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( "
    " );
    111     return 0;
    112 }
    View Code

     poj1436 Horizontally Visible Segments

    题目大意是,给出了很多条平行于y轴的线段,然后定义,两条线段能互相‘看见’的条件是,两条线段能由一条水平线连接,且这条水平线不能跟其他的所有线段有交点。

    而题目要求的是,3个线段能互相看见,这个条件下有多少组不同的。

    线段树区间覆盖,先按照x的坐标排序,然后每次覆盖前询问。。还有就是区间[1, 2] [3, 4]没有把区间[1,4]全部覆盖,所以线段树要开2倍,把输入的区间做乘2处理

     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 8005
    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 = mnx<<1;
    20 int cover[mnx<<3], used[mnx], n;
    21 struct seg{
    22     int l, r, x;
    23     bool operator < ( const seg & b ) const{
    24         return x < b.x;
    25     }
    26 }p[mnx];
    27 vector<int> g[mnx];
    28 void init(){
    29     memset( used, 0, sizeof(used) );
    30     memset( cover, 0, sizeof(cover) );
    31 }
    32 void pushdown( int rt ){
    33     if( cover[rt] ){
    34         cover[rt<<1] = cover[rt<<1|1] = cover[rt];
    35         cover[rt] = 0;
    36     }
    37 }
    38 void update( int L, int R, int v, int l, int r, int rt ){
    39     if( L <= l && R >= r ){
    40         cover[rt] = v;
    41         return ;
    42     }
    43     pushdown( rt );
    44     int m = ( l + r ) >> 1;
    45     if( L <= m ) update( L, R, v, lson );
    46     if( R > m ) update( L, R, v, rson );
    47 }
    48 void query( int L, int R, int v, int l, int r, int rt ){
    49     if( L <= l && R >= r ){
    50         if( cover[rt] ){
    51             if( used[cover[rt]] != v ){
    52                 used[cover[rt]] = v;
    53                 g[cover[rt]].push_back( v );
    54             }
    55             return ;
    56         }
    57     }
    58     if( l == r ) return ;
    59     pushdown( rt );
    60     int m = ( l + r ) >> 1;
    61     if( L <= m ) query( L, R, v, lson );
    62     if( R > m ) query( L, R, v, rson );
    63 }
    64 int main(){
    65     int cas;
    66     scanf( "%d", &cas );
    67     while( cas-- ){
    68         init();
    69         scanf( "%d", &n );
    70         for( int i = 1; i <= n; i++ ){
    71             scanf( "%d %d %d", &p[i].l, &p[i].r, &p[i].x );
    72             p[i].l <<= 1, p[i].r <<= 1;
    73         }
    74         sort( p + 1, p + n + 1 );
    75         for( int i = 1; i <= n; i++ ){
    76             query( p[i].l, p[i].r, i, 0, N, 1 );
    77             update( p[i].l, p[i].r, i, 0, N, 1 );
    78         }
    79         int ans = 0;
    80         for( int i = 1; i <= n; i++ ){
    81             int len1 = g[i].size();
    82             for( int j = 0; j < len1; j++ ){
    83                 int kk = g[i][j], len2 = g[kk].size();
    84                 for( int k = j + 1; k < len1; k++ ){
    85                     for( int m = 0; m < len2; m++ ){
    86                         if( g[i][k] == g[kk][m] ) ans++;
    87                     }
    88                 }
    89             }
    90             g[i].clear();
    91         }
    92         printf( "%d
    ", ans );
    93     }
    94     return 0;
    95 }
    View Code

     poj2991 Crane

    线段树加几何。。( c++过了,g++超时 ) 感觉有些时候g++快点,有些时候g++很慢,搞不懂有什么差别╮(╯▽╰)╭

    题意:给你一个n节组成的起重机,而每两节直接可以旋转,一开始每节都在y轴上,现在对于每次旋转第i与i+1的角度,求末端( 第N条线段的端点 )的坐标。。。

    线段树的节点保存三个信息: 向量的坐标( vx, vy ) 和 向量旋转的角度( ang )。。

    分析:    1.向量(x,y)则,向量 逆时针 旋转a弧度 后的向量为(cos a *x-sin a*y,sin a*x+cos a*y)

               2.向量的和刚好指向这些向量头尾相连后所指向的地方,也就是把每条线段看做一个向量,那么这项向量的和正好指向末端的坐标

               3.旋转第i与i+1的角度是,i+1及其上的所有向量旋转了同样的角度

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<string>
     5 #include<queue>
     6 #include<cmath>
     7 #include<vector>
     8 
     9 using namespace std;
    10 
    11 #define mnx 50005
    12 #define ll long long
    13 #define mod 1000000007
    14 #define inf 0x3f3f3f3f
    15 #define eps 1e-8
    16 #define Pi acos(-1.0);
    17 #define lson l, m, rt << 1
    18 #define rson m+1, r, rt << 1 | 1
    19 
    20 double vx[mnx], vy[mnx], ang[mnx], degree[mnx];
    21 void rotate( int rt, double rad ){
    22     rad = ( rad / 180.0 ) * Pi;
    23     double x = vx[rt] * cos( rad ) - vy[rt] * sin( rad );
    24     double y = vy[rt] * cos( rad ) + vx[rt] * sin( rad ); 
    25     vx[rt] = x, vy[rt] = y;
    26 }
    27 void pushup( int rt ){
    28     vx[rt] = vx[rt<<1] + vx[rt<<1|1];
    29     vy[rt] = vy[rt<<1] + vy[rt<<1|1];
    30 }
    31 void pushdown( int rt ){
    32     if( fabs( ang[rt] ) > eps ){
    33         rotate( rt<<1, ang[rt] );
    34         rotate( rt<<1|1, ang[rt] );
    35         ang[rt<<1] += ang[rt];
    36         ang[rt<<1|1] += ang[rt];
    37         ang[rt] = 0;
    38     }
    39 }
    40 void build( int l, int r, int rt ){
    41     ang[rt] = 0;
    42     if( l == r ){
    43         scanf( "%lf", &vy[rt] );
    44         vx[rt] = 0;
    45         return ;
    46     }
    47     int m = ( l + r ) >> 1;
    48     build( lson );
    49     build( rson );
    50     pushup( rt );
    51 }
    52 void update( int s, double a, int l, int r, int rt ){
    53     if( s < l ){
    54         rotate( rt, a );
    55         ang[rt] += a;
    56         return ;
    57     }
    58     pushdown( rt );
    59     int m = ( l + r ) >> 1;
    60     if( s < m ) update( s, a, lson );
    61     update( s, a, rson );
    62     pushup( rt );
    63 }
    64 int main(){
    65     int n, q, flag = 0;
    66     while( scanf( "%d %d", &n, &q ) != EOF ){
    67         if( flag ) puts( "" ); 
    68         flag = 1;
    69         build( 1, n, 1 ); 
    70         for( int i = 0; i <= n+2; i++ ) degree[i] = 180.0;
    71         while( q-- ){
    72             int s; double a;
    73             scanf( "%d %lf", &s, &a );
    74             update( s, a - degree[s+1], 1, n, 1 );
    75             degree[s+1] = a;
    76             printf( "%.2lf %.2lf
    ", vx[1], vy[1] );
    77         }
    78     }
    79     return 0;
    80 }
    View Code

     FZU 2163 多米诺骨牌

    中文题,不解释。。线段树区间更新,离散化。。找了好久的错,发现query里面还要sum[rt] = sum[rt<<1] + sum[rt<<1|1];因为我query的时候也改了sum[rt]的值,所以要向上更新,跪了好久。。其实还是逗比了,我应该写一个区间更新的update的,在query之后,然后对[l,r]进行区间更新的,然后再对[l,l]进行单点更新,就不会wa这么久了

    做法: 先按照x坐标又大到小排序,然后从右到左边查边插入线段树。。(这道题还可以用单调栈)

     1 #include<iostream>
     2 #include<cstring>
     3 #include<cstdio>
     4 #include<algorithm>
     5 #include<string>
     6 #include<cmath>
     7 #include<map>
     8 #include<queue>
     9 
    10 using namespace std;
    11 
    12 #define mnx 200005
    13 #define Pi acos(-1.0)
    14 #define ull unsigned long long
    15 #define ll long long 
    16 #define inf 0x3f3f3f3f
    17 #define eps 1e-8
    18 #define MP make_pair
    19 #define lson l, m, rt << 1
    20 #define rson m+1, r, rt << 1 | 1
    21 #define mod 2333333
    22 
    23 const int N = mnx - 2;
    24 int ch[mnx<<2], sum[mnx<<2], col[mnx<<2], ans[mnx];
    25 struct domino{
    26     int x, h, id;
    27     bool operator < ( const domino & b ) const{
    28         return x > b.x;
    29     }
    30 }p[mnx];
    31 int bin_search( int key, int n ){
    32     return lower_bound( ch + 1, ch + n + 1, key ) - ch;
    33 }
    34 void pushdown( int rt ){
    35     if( col[rt] ){
    36         sum[rt<<1] = sum[rt<<1|1] = 0;
    37         col[rt<<1] = col[rt<<1|1] = 1;
    38         col[rt] = 0;
    39     }
    40 }
    41 void update( int k, int v, int l, int r, int rt ){
    42     if( l == r ){
    43         sum[rt] = v;
    44         return ;
    45     }
    46     pushdown( rt );
    47     int m = ( l + r ) >> 1;
    48     if( k <= m ) update( k, v, lson );
    49     else update( k, v, rson );
    50     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    51 }
    52 int query( int L, int R, int l, int r, int rt ){
    53     int ret = 0;
    54     if( L <= l && R >= r ){
    55         col[rt] = 1, ret = sum[rt], sum[rt] = 0; 
    56         return ret;
    57     }
    58     pushdown( rt );
    59     int m = ( l + r ) >> 1;
    60     if( L <= m ) ret += query( L, R, lson );
    61     if( R > m ) ret += query( L, R, rson );
    62     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    63     return ret;
    64 }
    65 int main(){
    66     int n;
    67     while( scanf( "%d", &n ) != EOF ){
    68         memset( col, 0, sizeof(col) );
    69         memset( sum, 0, sizeof(sum) );
    70         int l, r, cnt = 1;    
    71         for( int i = 1; i <= n; i++ ){    
    72             scanf( "%d %d", &l, &r );
    73             p[i].x = l, p[i].h = r, p[i].id = i;
    74             ch[cnt++] = l, ch[cnt++] = r + l - 1;
    75         }
    76         sort( ch + 1, ch + cnt );
    77         cnt = unique( ch + 1, ch + cnt ) - ch - 1;
    78         sort( p + 1, p + n + 1 );
    79         for( int i = 1; i <= n; i++ ){
    80             l = bin_search( p[i].x, cnt );
    81             r = bin_search( p[i].h + p[i].x - 1, cnt );
    82             ans[p[i].id] = query( l, r, 1, N, 1 ) + 1;
    83             update( l, ans[p[i].id], 1, N, 1 );
    84         } 
    85         for( int i = 1; i <= n; i++ ){
    86             printf( "%d%c", ans[i], i == n ? '
    ' : ' ' );
    87         }
    88     }
    89     return 0;
    90 }
    View Code

    hdu 4973  A simple simulation problem

    尼玛,跪了一个晚上,终于检查出错误了。。下午的做法想线段树每个节点记录三个值l, r, sum,最后写了两个小时,没有过,哎。。晚上听小坤子讲了他的做法,敲出来了,然后一直不能ac,最后还是他帮我找出错误。。敲代码还是细心细心啊。。

    做法:sum[]维护的是节点内数的个数,cnt[]维护的是这个节点内,不同数的个数的最大值,col[]记录这个区间内的数复制了多少次。。输入要更新和要询问的区间[l, r],先查找 l 在哪个节点(假设为L)上,  r 在哪个节点(假设为R)上,再更新或询问( L + 1, R + 1 )这个区间

      1 #include<iostream>
      2 #include<cstring>
      3 #include<cstdio>
      4 #include<string>
      5 #include<queue>
      6 #include<algorithm>
      7 #include<cmath>
      8 #include<vector>
      9 
     10 using namespace std;
     11 
     12 #define mnx 50050
     13 #define ll long long
     14 #define mod 1000000007
     15 #define inf 0x3f3f3f3f
     16 #define eps 1e-10
     17 #define Pi acos(-1.0);
     18 #define lson l, m, rt << 1
     19 #define rson m+1, r, rt << 1 | 1
     20 
     21 ll sum[mnx<<2], ls, rs, cnt[mnx<<2];
     22 int col[mnx<<2];
     23 void pushup( int rt ){
     24     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
     25     cnt[rt] = max( cnt[rt<<1], cnt[rt<<1|1] );
     26 }
     27 void pushdown( int rt ){
     28     if( col[rt] ){
     29         col[rt<<1] += col[rt];
     30         col[rt<<1|1] += col[rt];
     31         int k = col[rt];
     32         sum[rt<<1] <<= k;
     33         sum[rt<<1|1] <<= k;
     34         cnt[rt<<1] <<= k;
     35         cnt[rt<<1|1] <<= k;
     36         col[rt] = 0; 
     37     }
     38 }
     39 void build( int l, int r, int rt ){
     40     col[rt] = 0;
     41     if( l == r ){
     42         sum[rt] = 1, cnt[rt] = 1;
     43         return ;
     44     }
     45     int m = ( l + r ) >> 1;
     46     build( lson ); build( rson );
     47     pushup( rt );
     48 }
     49 int find( int t, int x, int l, int r, int rt ){
     50     if( l == r ){
     51         if( t == 0 ){
     52             rs = sum[rt] - x + 1;
     53         }
     54         if( t == 1 ){
     55             ls = x;
     56         }
     57         return l;
     58     }
     59     pushdown( rt );
     60     int m = ( l + r ) >> 1;
     61     if( x <= sum[rt<<1] ) return find( t, x, lson );
     62     else return find( t, x - sum[rt<<1], rson );
     63 }
     64 void update1( int x, int v, int l, int r, int rt ){
     65     if( l == r ){
     66         sum[rt] += v;
     67         cnt[rt] += v;
     68         return ;
     69     }
     70     pushdown( rt );
     71     int m = ( l + r ) >> 1;
     72     if( x <= m ) update1( x, v, lson );
     73     else update1( x, v, rson );
     74     pushup( rt );
     75 }
     76 void update2( int L, int R, int l, int r, int rt ){
     77     if( L <= l && R >= r ){
     78         col[rt] += 1;
     79         sum[rt] <<= 1;
     80         cnt[rt] <<= 1;
     81         return ;
     82     }
     83     pushdown( rt );
     84     int m = ( l + r ) >> 1;
     85     if( L <= m ) update2( L, R, lson );
     86     if( R > m ) update2( L, R, rson );
     87     pushup( rt );
     88 }
     89 ll query( int L, int R, int l, int r, int rt ){
     90     if( L <= l && R >= r ){
     91         return cnt[rt];
     92     }
     93     pushdown( rt );
     94     int m = ( l + r ) >> 1; ll ret = -1;
     95     if( L <= m ) ret = max( ret, query( L, R, lson ) );
     96     if( R > m ) ret = max( ret, query( L, R, rson ) );
     97     return ret;
     98 }
     99 int main(){
    100     //freopen( "out.txt", "w", stdout );
    101     int cas, kcnt = 1, n, m;
    102     scanf( "%d", &cas );
    103     while( cas-- ){
    104         scanf( "%d %d", &n, &m );
    105         build( 1, n, 1 );
    106         char ch[2];
    107         int l, r;
    108         printf( "Case #%d:
    ", kcnt++ );
    109         while( m-- ){
    110             scanf( "%s %d %d", &ch, &l, &r );
    111             if( ch[0] == 'D' ){
    112                 int L = find( 0, l, 1, n, 1 );
    113                 int R = find( 1, r, 1, n, 1 );
    114                 if( L == R ){
    115                     update1( L, r - l + 1, 1, n, 1 );
    116                 }
    117                 else{
    118                     update1( L, rs, 1, n, 1 );
    119                     update1( R, ls, 1, n, 1 );
    120                     if( L + 1 <= R - 1 ) update2( L + 1, R - 1, 1, n, 1 );
    121                 }
    122             }
    123             else{
    124                 int L = find( 0, l, 1, n, 1 );
    125                 int R = find( 1, r, 1, n, 1 );
    126                 if( L == R ){
    127                     printf( "%d
    ", r - l + 1 );
    128                 }
    129                 else{
    130                     ll ans = max( ls, rs );
    131                     if( L + 1 <= R - 1 ) ans = max( ans, query( L + 1, R - 1, 1, n, 1 ) );
    132                     printf( "%I64d
    ", ans );
    133                 }
    134             }
    135         }
    136     }
    137     return 0;
    138 }
    View Code

     ZOJ 3686 A Simple Tree Problem

    给你一棵树,所有的节点初始为0。给你一个节点u,有两种操作,一种是把u及其子节点全部翻转( 0 -> 1, 1 -> 0 ),第二种操作就是问你 u及其子节点有多少个1。。

    先dfs整棵树,记录每棵子树的区间,假设有n个节点,树根在的节点就是[1,n]。然后就可以用线段树成段更新了。翻转的时候是sum[rt] = r - l + 1 - sum[rt];

     1 #include <iostream>
     2 #include <cstdio>
     3 #include <cstring>
     4 #include <cmath>
     5 #include <vector>
     6 #include <algorithm>
     7 
     8 using namespace std;
     9 
    10 #define LL long long
    11 #define eps 1e-8
    12 #define lson l, m, rt<<1
    13 #define rson m+1, r, rt<<1|1
    14 #define mnx 100010
    15 
    16 int n, fst[mnx], vv[mnx], nxt[mnx], e;
    17 struct node{
    18     int L, R;
    19 }g[mnx];
    20 void add( int u, int v ){
    21     vv[e] = v, nxt[e] = fst[u], fst[u] = e++;
    22 }
    23 int c;
    24 int dfs( int u ){
    25     g[u].L = ++c;
    26     for( int i = fst[u]; i != -1; i = nxt[i] )
    27         dfs( vv[i] );
    28     g[u].R = c;
    29 }
    30 int Xor[mnx<<2], sum[mnx<<2];
    31 void pushdown( int rt, int L, int R ){
    32     int m = ( L + R ) >> 1;
    33     if( Xor[rt] ){
    34         Xor[rt<<1] ^= 1, Xor[rt<<1|1] ^= 1, Xor[rt] = 0;
    35         sum[rt<<1] = m - L + 1 - sum[rt<<1];
    36         sum[rt<<1|1] = R - m - sum[rt<<1|1];
    37     }
    38 }
    39 void pushup( int rt ){
    40     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
    41 }
    42 void update( int L, int R, int l, int r, int rt ){
    43     if( L <= l && R >= r ){
    44         Xor[rt] ^= 1;
    45         sum[rt] = r - l + 1 - sum[rt];
    46         return ;
    47     }
    48     pushdown( rt, l, r );
    49     int m = ( l + r ) >> 1;
    50     if( L <= m ) update( L, R, lson );
    51     if( R > m ) update( L, R, rson );
    52     pushup( rt );
    53 }
    54 int query( int L, int R, int l, int r, int rt ){
    55     if( L <= l && R >= r ){
    56         return sum[rt];
    57     }
    58     pushdown( rt, l, r );
    59     int m = ( l + r ) >> 1, ret = 0;
    60     if( L <= m ) ret += query( L, R, lson );
    61     if( R > m ) ret += query( L, R, rson );
    62    // pushup( rt );
    63     return ret;
    64 }
    65 int main(){
    66     int m;
    67     while( scanf( "%d%d", &n, &m ) != EOF ){
    68         memset( sum, 0, sizeof(sum) );
    69         memset( Xor, 0, sizeof(Xor) );
    70         memset( fst, -1, sizeof(fst) );
    71         c = e = 0;
    72         int v;
    73         for( int i = 2; i <= n; ++i ){
    74             scanf( "%d", &v );
    75             add( v, i );
    76         }
    77         dfs( 1 );
    78         while( m-- ){
    79             char c[3];
    80             scanf( "%s", c );
    81             scanf( "%d", &v );
    82             if( c[0] == 'o' )
    83                 update( g[v].L, g[v].R, 1, n, 1 );
    84             else
    85                 printf( "%d
    ", query( g[v].L, g[v].R, 1, n, 1 ) );
    86         }
    87         puts( "" );
    88     }
    89     return 0;
    90 }
    View Code
  • 相关阅读:
    散列
    AVL树的单旋与双旋
    Ubuntu系统目录
    os x文件系统结构简介
    c语言静态局部变量
    创建J2EE 5.0工程后,JSTL不能使用解决方法
    mysql
    指针
    servlet 访问项目
    c数组
  • 原文地址:https://www.cnblogs.com/LJ-blog/p/3911347.html
Copyright © 2020-2023  润新知