线段树专题

HDU 1166 敌兵布阵 (单点更新,区间求和)

接下来每行有一条命令,命令有4种形式:
(1) Add i j,i和j为正整数,表示第i个营地增加j个人(j不超过30)
(2)Sub i j ,i和j为正整数,表示第i个营地减少j个人(j不超过30);
(3)Query i j ,i和j为正整数,i<=j,表示询问第i到第j个营地的总人数;
(4)End 表示结束,这条命令在每组数据最后出现;
const int Max_N = 50100 ;
int sum[Max_N<<2] , x[Max_N] ;

void push_up(int root){
     sum[root] = sum[root<<1] + sum[root<<1|1] ;
}

void make_tree(int L , int R , int root){
     if(L == R){
        sum[root] = x[L] ;
        return  ;
     }
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
     push_up(root) ;
}

void update(int id , int c , int L , int R , int root){
     if(L == R){
        sum[root] += c ;
        return ;
     }
     int mid = (L + R) >> 1 ;
     if(id <= mid)
        update(id , c , L , mid ,root<<1) ;
     else
        update(id , c , mid+1 , R , root<<1|1) ;
     push_up(root) ;
}

int query(int l , int r , int L , int R ,int root){
    if(l <= L && R <= r)
       return sum[root] ;
    int mid = (L + R) >> 1 ;
    int ans = 0 ;
    if(l <= mid)
       ans += query(l , r , L , mid , root<<1) ;
    if(r > mid)
       ans += query(l , r , mid+1 , R , root<<1|1) ;
    return ans ;
}

int main(){
    int T , n , i , a , b ;
    char str[8] ;
    cin>>T ;
    for(int cas = 1 ; cas <= T ; cas++){
        printf("Case %d:\n",cas) ;
        scanf("%d",&n) ;
        for(i = 1 ; i <= n ; i++)
            scanf("%d",&x[i]) ;
        make_tree(1,n,1) ;
        while(scanf("%s",str) && strcmp(str,"End")!=0){
            scanf("%d%d",&a,&b) ;
            if(str[0] == 'A')
               update(a , b , 1 , n , 1) ;
            else if(str[0] == 'S')
               update(a , -b , 1 , n , 1) ;
            else
               printf("%d\n",query(a , b , 1 , n , 1)) ;
        }
    }
    return 0 ;
}

  

HDU 1394 Minimum Inversion Number (逆序对 , 单点更新,区间求和)

序列的N个置换,求N串中逆序对最小的值。
a1, a2, ..., an-1, an (where m = 0 - the initial seqence)
a2, a3, ..., an, a1 (where m = 1)
a3, a4, ..., an, a1, a2 (where m = 2)
...
an, a1, a2, ..., an-1 (where m = n-1)
You are asked to write a program to find the minimum inversion number out of the above sequences. 

const int Max_N = 5008  ;
int   Sum[Max_N<<1] ,x[Max_N];

void  push_up(int root){
      Sum[root] = Sum[root<<1] + Sum[root<<1|1] ;
}

void  make_tree(int L , int R , int root){
      if(L == R){
           Sum[root] = 0 ;
           return ;
      }
      int mid = (L + R) >> 1 ;
      make_tree(L , mid , root<<1) ;
      make_tree(mid+1 , R , root<<1|1) ;
      push_up(root) ;
}

void  update(int id , int L , int R , int root){
      if(L == R){
           Sum[root]++ ;
           return ;
      }
      int mid = (L + R) >> 1 ;
      if(id <= mid)
         update(id , L , mid , root<<1) ;
      else
         update(id , mid+1 , R , root<<1|1) ;
      push_up(root) ;
}

int   query(int l , int r , int L , int R , int root){
      if(l <= L && R <= r)
         return Sum[root] ;
      int mid = (L + R) >> 1 ;
      int ans = 0 ;
      if(l <= mid)
          ans += query(l , r , L , mid , root<<1) ;
      if(r > mid)
          ans += query(l , r , mid+1 , R , root<<1|1) ;
      return ans ;
}

int main(){
    int n , i  , sum  , ans ;
    while(cin>>n){
        make_tree(1 , n , 1) ;  //建一颗空树
        sum = 0 ;
        for(i = 1 ; i <= n ; i++){
            scanf("%d",&x[i]) ;
            x[i]++ ;          // 序列变为[1,n]
            sum += query(x[i] , n , 1 , n , 1) ; //  [x[i] , n]出现的个数之和 , 也就是在大于x[i],且位置在起左边的个数 
            update(x[i] , 1 , n , 1) ;  //在x[i]位置插入1  
        }
        ans = sum ;   // sum即为初始序列逆序数
        for(i = 1 ; i < n ; i++){
            // 将想x[i]移到尾巴。逆序数变化情况。 x[i]在头少了(x[i] -1 ) ,x[i] 在尾多了(n-x[i])个 ,总计多了: +(n-x[i])-(x[i]-1)
            sum = sum + n - x[i] - x[i] + 1 ;  
            ans = min(ans ,sum) ;
        }
        printf("%d\n",ans) ;
    }
    return 0 ;
}

HDU 1754 I Hate It (单点更新,区间最值)

接下来有M行。每一行有一个字符 C (只取'Q'或'U') ,和两个正整数A,B。
当C为'Q'的时候,表示这是一条询问操作,它询问ID从A到B(包括A,B)的学生当中,成绩最高的是多少。
当C为'U'的时候,表示这是一条更新操作,要求把ID为A的学生的成绩更改为B。
 
 
Output
对于每一次询问操作,在一行里面输出最高成绩。
 
 
Sample Input
5 61 2 3 4 5Q 1 5U 3 6Q 3 4Q 4 5U 2 9Q 1 5
 
 
Sample Output
5 6 5 9

 

const int Max_N = 200100 ;
int Max[Max_N<<2] , x[Max_N] ;

void push_up(int root){
     Max[root] = max(Max[root<<1] , Max[root<<1|1]) ;
}

void make_tree(int L , int R , int root){
     if(L == R){
        Max[root] = x[L] ;
        return ;
     }
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
     push_up(root) ;
}

void update(int id , int c , int L , int R , int root){
     if(L == R){
        Max[root] = c ;
        return ;
     }
     int mid = (L + R) >> 1 ;
     if(id <= mid)
        update(id , c , L , mid ,root<<1) ;
     else
        update(id , c , mid+1 , R ,root<<1|1) ;
     push_up(root) ;
}

int query(int l , int r , int L , int R , int root){
    if(l <= L && R <= r)
      return Max[root] ;
    int mid = (L + R) >> 1 ;
    int ans = -1 ;
    if(l <= mid)
        ans = max(ans , query(l , r , L , mid , root<<1)) ;
    if(r > mid)
        ans = max(ans , query(l , r , mid+1 , R , root<<1|1)) ;
    return ans ;
}

int main(){
    int n , m , i , a , b ;
    char str[2] ;
    while(cin>>n>>m){
        for(i = 1 ; i <= n ; i++)
            scanf("%d",&x[i]) ;
        make_tree(1 , n , 1) ;
        while(m--){
            scanf("%s%d%d",str,&a,&b) ;
            if(*str == 'U')
               update(a , b , 1 , n , 1) ;
            else
               printf("%d\n",query(a , b , 1 , n , 1)) ;
        }
    }
    return 0 ;
}

  

POJ 4047 区间更新 , 区间最值

const int Max_N = 200010 ;
int  x[Max_N] , sum[Max_N]  , num[Max_N]  ;
int  N , K ;
int  _max[Max_N<<2]  , add[Max_N<<2] ;

void push_up(int root){
     _max[root] = max(_max[root<<1] , _max[root<<1|1]) ;
}

void push_down(int root){
     if(add[root]){
          add[root<<1] += add[root] ;
          add[root<<1|1] += add[root] ;
          _max[root<<1] += add[root] ;
          _max[root<<1|1] += add[root] ;
          add[root] = 0 ;
     }
}

void make_tree(int L , int R , int root){
     add[root] = 0 ;
     if(L == R){
          _max[root] = num[L] ;
          return ;
     }
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
     push_up(root) ;
}

void update(int l , int r , int c , int L , int R , int root){
     if(l <= L && R <= r){
          add[root]  += c ;
          _max[root] += c ;
          return ;
     }
     push_down(root) ;
     int mid = (L + R) >> 1 ;
     if(l <= mid)
         update(l , r , c , L , mid , root<<1) ;
     if(r > mid)
         update(l , r , c , mid+1 , R , root<<1|1) ;
     push_up(root) ;
}

int query(int l , int r , int L , int R , int root){
    if(l <= L && R <= r)
        return _max[root] ;
    push_down(root) ;
    int mid = (L + R) >> 1 ;
    int ans = -0xfffffff ;
    if(l <= mid)
         ans = max(ans, query(l , r , L , mid , root<<1) ) ;
    if(r > mid)
         ans = max(ans , query(l , r , mid+1 , R , root<<1|1) );
    return ans ;
}

int  main(){
     int  t , i , j  , M  , a , b , c , p ;
     scanf("%d" ,&t) ;
     while(t--){
          scanf("%d%d%d" ,&N ,&M ,&K) ;
          sum[0] = 0 ;
          for(i = 1 ; i <= N ; i++){
               scanf("%d" ,&x[i]) ;
               sum[i] = x[i] + sum[i-1] ;
          }
          for(i = K  ; i <= N ; i++)
              num[i-K+1] = sum[i] - sum[i-K] ;
          N = N - K + 1 ;
          make_tree(1 , N , 1) ;
          while(M--){
               scanf("%d%d%d" ,&p , &a , &b) ;
               if(p == 0){
                    if(x[a] != b){
                        c = b - x[a] ;
                        x[a] = b ;
                        update(max(a-K+1,1) , a , c , 1 , N , 1) ;
                    }
               }
               else if(p == 1){
                    if(a != b){
                        c = x[b] - x[a] ;
                        update(max(a-K+1,1) , a , c , 1 , N , 1) ;
                        c = x[a] - x[b] ;
                        update(max(b-K+1,1) , b , c , 1 , N , 1) ;
                        swap(x[a] , x[b]) ;
                    }
               }
               else{
                   printf("%d\n" , query(a, b-K+1 , 1 , N , 1)) ;
               }
          }
     }
     return 0 ;
}






Codeforces 91B. Queue (区间“最值”)

There are n walruses standing in a queue in an airport. They are numbered starting from the queue's tail: the 1-st walrus stands at the end of the queue and the n-th walrus stands at the beginning of the queue. The i-th walrus has the age equal to ai.

The i-th walrus becomes displeased if there's a younger walrus standing in front of him, that is, if exists such j (i < j), that ai > aj. Thedispleasure of the i-th walrus is equal to the number of walruses between him and the furthest walrus ahead of him, which is younger than the i-th one. That is, the further that young walrus stands from him, the stronger the displeasure is.

The airport manager asked you to count for each of n walruses in the queue his displeasure.

Input

The first line contains an integer n (2 ≤ n ≤ 105) — the number of walruses in the queue. The second line contains integers ai (1 ≤ ai ≤ 109).

Note that some walruses can have the same age but for the displeasure to emerge the walrus that is closer to the head of the queue needs to be strictly younger than the other one.

Output

Print n numbers: if the i-th walrus is pleased with everything, print "-1" (without the quotes). Otherwise, print the i-th walrus's displeasure: the number of other walruses that stand between him and the furthest from him younger walrus.

Sample test(s)
 
input
6
10 8 5 3 50 45
output
2 1 0 -1 0 -1 
input
7
10 4 6 3 2 8 15
output
4 2 1 0 -1 -1 -1 
input
5
10 3 1 10 11
output
1 0 -1 -1 -1 

  题意: 
  有n个数的失望值,id失望值的定义是:id右边离它最远的且比它小的数 与 它本身之间 间隔的数的数量;
线段树,结点保存区间最小值 每次将当前的数更新为INF,然后查找整个区间内最右边的比它小的数的下标 .

const int Max_N = 100008 ;
const int inf = 1000000800 ;
int   _Min[Max_N<<2] , x[Max_N]  , ans[Max_N] ;

void  push_up(int root){
      _Min[root] = min(_Min[root<<1] , _Min[root<<1|1]) ;
}

void  make_tree(int L , int R , int root){
      if(L == R){
          _Min[root] = x[L] ;
          return ;
      }
      int mid = (L + R) >> 1 ;
      make_tree(L , mid , root<<1) ;
      make_tree(mid+1 , R , root<<1|1) ;
      push_up(root) ;
}

void  update(int id ,  int L , int R , int root){
      if(L == R){
          _Min[root] = inf ;
          return ;
      }
      int mid = (L + R) >> 1 ;
      if(id <= mid)
           update(id , L , mid , root<<1) ;
      else
           update(id , mid+1 , R , root<<1|1) ;
      push_up(root) ;
}

//求区间[L,R]中 比C小 且 下标最大 的下标  。 其实二叉树遍历蛮重要的。 先右->后左。{好像不是3种遍历方式哦!}
int   query(int c , int L , int R , int root){    
      if(L == R)
         return L ;
      int mid = (L + R) >> 1 ;
      if(_Min[root<<1|1] < c)   //右孩子的最小值比C小,则在右孩子中找 。
         return query(c , mid+1 , R , root<<1|1) ;
      else
         return query(c , L , mid , root<<1) ;
}

int main(){
    int n , i ;
    cin>>n ;
    for(i = 1 ; i <= n ; i++)
        scanf("%d" , &x[i]) ;
    make_tree(1 , n , 1) ;
    for(i = 1 ; i <= n ; i++){
        update(i , 1 , n , 1) ;  //将i处更新最大,更新完之后,_Min[1] = [1,n]最小值
        if(_Min[1] < x[i])
            ans[i] = query(x[i] , 1 , n , 1) - i - 1 ;  // 为什么不能是query(x[i] , i , n , 1) ?因为[i,n]的节点编号不是1。注意这里
        else
            ans[i] = -1 ;
    }
    printf("%d" , ans[1]) ;
    for(i = 2 ; i <= n ; i++)
        printf(" %d" , ans[i]) ;
    puts("") ;
    return 0 ;
}

  

 

hdu 1698  (区间更新)

Just a Hook

 

Problem Description
In the game of DotA, Pudge’s meat hook is actually the most horrible thing for most of the heroes. The hook is made up of several consecutive metallic sticks which are of the same length.




Now Pudge wants to do some operations on the hook.

Let us number the consecutive metallic sticks of the hook from 1 to N. For each operation, Pudge can change the consecutive metallic sticks, numbered from X to Y, into cupreous sticks, silver sticks or golden sticks.
The total value of the hook is calculated as the sum of values of N metallic sticks. More precisely, the value for each kind of stick is calculated as follows:

For each cupreous stick, the value is 1.
For each silver stick, the value is 2.
For each golden stick, the value is 3.

Pudge wants to know the total value of the hook after performing the operations.
You may consider the original hook is made up of cupreous sticks.
 

 

Input
The input consists of several test cases. The first line of the input is the number of the cases. There are no more than 10 cases.
For each case, the first line contains an integer N, 1<=N<=100,000, which is the number of the sticks of Pudge’s meat hook and the second line contains an integer Q, 0<=Q<=100,000, which is the number of the operations.
Next Q lines, each line contains three integers X, Y, 1<=X<=Y<=N, Z, 1<=Z<=3, which defines an operation: change the sticks numbered from X to Y into the metal kind Z, where Z=1 represents the cupreous kind, Z=2 represents the silver kind and Z=3 represents the golden kind.
 

 

Output
For each case, print a number in a line representing the total value of the hook after the operations. Use the format in the example.
 

 

Sample Input
11021 5 25 9 3
 

 

Sample Output
Case 1: The total value of the hook is 24.
 
typedef long long LL ;
const int Max_N = 100008 ;
int sum[Max_N<<2] ;  /*和*/
int color[Max_N<<2] ;/*颜色,-1表示不是纯色*/

/*向上更新,计算和*/
void push_up(int root){
     sum[root] = sum[root<<1] + sum[root<<1|1] ;
}

/*lazy操作,向下更新时,把纯色的颜色传递下去,同时更新和,若不是纯色则孩子节点的颜色之前已经更新*/
void push_down(int root ,int L ,int R){
     if(color[root] != -1){
         color[root<<1] = color[root<<1|1] = color[root] ;
         color[root] = -1 ;  /*向下更新就是因为root节点不再纯色*/
         int mid = (L+R)>>1 ;
         sum[root<<1] = (mid-L+1) * color[root<<1] ;
         sum[root<<1|1] = (R-mid) * color[root<<1|1] ;
     }
}

/*建树*/
void make_tree(int L , int R , int root){
     color[root] = 1 ;
     if(L == R){
        sum[root] =  1 ;
        return ;
     }
     int mid = (L+R)>>1 ;
     make_tree(L,mid,root<<1) ;
     make_tree(mid+1,R,root<<1|1) ;
     push_up(root) ;
}

/*更新区间[l,r]颜色为c*/
void update(int l , int r , int c ,int L ,int R ,int root){
     if(l <= L && R <= r){
        color[root] = c ;
        sum[root] = (R-L+1) * c ;
        return ;
     }
     push_down(root,L,R) ; 
     int mid = (L+R)>>1 ;
     if(l <= mid)
        update(l,r,c,L,mid,root<<1) ;
     if(r > mid)
        update(l,r,c,mid+1,R,root<<1|1) ;
     push_up(root) ;
}

int main(){
    int T ,cas , n ,q , l ,r ,c;
    scanf("%d",&T) ;
    for(cas = 1 ; cas <= T ; cas++){
        scanf("%d",&n) ;
        make_tree(1,n,1) ;
        scanf("%d",&q) ;
        while(q--){
             scanf("%d%d%d",&l,&r,&c) ;
             update(l,r,c,1,n,1) ;
        }
        printf("Case %d: The total value of the hook is %d.\n",cas,sum[1]) ;
    }
    return 0 ;
}

 

fzu1608 Huge Mission (区间更新,区间最值)

   区间【L, R】染色c  ,每个点都取最大值。

   求整个区间最大和。

const int Max_N = 50008 ;
int color[Max_N<<2] ;

void  push_down(int root){
      if(color[root] != -1){
           color[root<<1]   =  max(color[root<<1],color[root]) ;
           color[root<<1|1] =  max(color[root<<1|1],color[root]) ;
           color[root] = -1 ;
      }
      return ;
}

void make_tree(int L , int R , int root){
     color[root] = 0 ;
     if(L == R)
        return ;
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
}

void update(int l , int r , int c , int L , int R , int root){
     if(l <= L && R <= r){
        if(color[root] < c)
           color[root] = c ;
        return  ;
     }
     push_down(root) ;
     int mid = (L + R) >> 1 ;
     if(l <= mid)
        update(l , r , c , L , mid , root<<1) ;
     if(r > mid)
        update(l , r , c , mid+1 , R , root<<1|1) ;
}

int query(int L , int R , int root){
    if(L == R)
        return color[root] ;
    push_down(root) ;
    int mid = (L + R) >> 1 ;
    return query(L , mid , root<<1) + query(mid+1 , R ,root<<1|1) ;
}

int main(){
    int n , m , l , r , c ;
    while(scanf("%d%d" ,&n ,&m) != EOF){
        make_tree(0 , n , 1) ;
        while(m--){
            l = getint() ;
            r = getint() ;
            c = getint() ;
            if(c)
                update(l , r-1 , c , 0 , n , 1) ;
        }
        printf("%d\n" , query(0 , n , 1)) ;
    }
    return 0 ;
}


 

POJ 3468 (区间更新)

A Simple Problem with Integers
Time Limit: 5000MS   Memory Limit: 131072K
     

You have N integers, A1A2, ... , 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.

Input

The first line contains two numbers N and Q. 1 ≤ N,Q ≤ 100000.
The second line contains N numbers, the initial values of A1A2, ... , AN. -1000000000 ≤ Ai ≤ 1000000000.
Each of the next Q lines represents an operation.
"C a b c" means adding c to each of AaAa+1, ... , Ab. -10000 ≤ c ≤ 10000.
"Q a b" means querying the sum of AaAa+1, ... , Ab.

Output

You need to answer all Q commands in order. One answer in a line.

Sample Input

10 5
1 2 3 4 5 6 7 8 9 10
Q 4 4
Q 1 10
Q 2 4
C 3 6 3
Q 2 4

Sample Output

4
55
9
15

Hint

The sums may exceed the range of 32-bit integers.
typedef long long LL ;
const int Max_N = 101000 ;
LL sum[Max_N<<2] , add[Max_N<<2] , x[Max_N];

void push_up(int root){
     sum[root] = sum[root<<1] + sum[root<<1|1] ;
}

void push_down(int L ,int R ,int root){
     if(add[root]){  //纯色才向下更新。
          add[root<<1] += add[root] ;
          add[root<<1|1] += add[root] ;
          int mid = (L + R)>>1 ;
          sum[root<<1] += add[root]*(mid-L+1) ;
          sum[root<<1|1] += add[root]*(R-mid) ;
          add[root] = 0 ; //更新完便不再是纯色了。
     }
}

void make_tree(int L ,int R,int root){
     add[root] = 0 ;
     if(L == R){
        sum[root] = x[L] ;
        return ;
     }
     int mid = (L + R)>>1 ;
     make_tree(L,mid,root<<1) ;
     make_tree(mid+1,R,root<<1|1) ;
     push_up(root) ;
}

void update(int l ,int r ,LL c ,int L ,int R ,int root){
     if(l <= L && R <= r){
         add[root] += c ;
         sum[root] += c*(R-L+1) ;
         return ;
     }
     push_down(L,R,root) ;
     int mid = (L + R)>>1 ;
     if(l <= mid)
        update(l,r,c,L,mid,root<<1) ;
     if(r > mid)
        update(l,r,c,mid+1,R,root<<1|1) ;
     push_up(root) ;
}

LL   query(int l ,int r ,int L ,int R ,int root){
     if(l <= L && R <= r)
        return sum[root] ;
     push_down(L,R,root) ; // update中push_down的时候并没有把所有该更新的更新完。
     int mid = (L + R)>>1 ;
     LL ans = 0 ;
     if(l <= mid)
        ans += query(l,r,L,mid,root<<1) ;
     if(r > mid)
        ans += query(l,r,mid+1,R,root<<1|1) ;
     return ans ;
}

int main(){
    int i , n , q ,l,r;
    LL c;
    char str[2] ;
    cin>>n>>q ;
    for(i = 1 ; i <= n ; i++)
        scanf("%lld",&x[i]) ;
    make_tree(1,n,1) ;
    while(q--){
        scanf("%s%d%d",str,&l,&r) ;
        if(str[0] == 'Q')
           printf("%lld\n",query(l,r,1,n,1)) ;
        else{
           scanf("%lld",&c) ;
           update(l,r,c,1,n,1) ;
        }
    }
    return 0 ;
}

 

HDU 4027  Can you answer these queries?(区间更新)

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)


Problem Description
A lot of battleships of evil are arranged in a line before the battle. Our commander decides to use our secret weapon to eliminate the battleships. Each of the battleships can be marked a value of endurance. For every attack of our secret weapon, it could decrease the endurance of a consecutive part of battleships by make their endurance to the square root of it original value of endurance. During the series of attack of our secret weapon, the commander wants to evaluate the effect of the weapon, so he asks you for help.
You are asked to answer the queries that the sum of the endurance of a consecutive part of the battleship line.

Notice that the square root operation should be rounded down to integer.
 

 

Input
The input contains several test cases, terminated by EOF.
  For each test case, the first line contains a single integer N, denoting there are N battleships of evil in a line. (1 <= N <= 100000)
  The second line contains N integers Ei, indicating the endurance value of each battleship from the beginning of the line to the end. You can assume that the sum of all endurance value is less than 2 63.
  The next line contains an integer M, denoting the number of actions and queries. (1 <= M <= 100000)
  For the following M lines, each line contains three integers T, X and Y. The T=0 denoting the action of the secret weapon, which will decrease the endurance value of the battleships between the X-th and Y-th battleship, inclusive. The T=1 denoting the query of the commander which ask for the sum of the endurance value of the battleship between X-th and Y-th, inclusive.
 

 

Output
For each test case, print the case number at the first line. Then print one line for each query. And remember follow a blank line after each test case.
 

 

Sample Input
10
1 2 3 4 5 6 7 8 9 10
5
0 1 10
1 1 10
1 1 5
0 5 8
1 4 8
 Sample Output
Case #1:
19
7
6
 由于--》1很快,所以在有限的更新次数内,区间容易变为全是1. 用color来标记 。
当color【root】 = 1 时则不用往下继续更新。
typedef long long LL ;
const int Max_N = 100100 ;
LL sum[Max_N<<2] , x[Max_N] ;
int color[Max_N<<2] ;
void push_up(int root){
     sum[root] = sum[root<<1] + sum[root<<1|1] ;
     color[root] = color[root<<1] && color[root<<1|1] ;
}

void make_tree(int L , int R , int root){
     if(L == R){
        sum[root] = x[L] ;
        color[root]  =  sum[root] == 1 ;
        return ;
     }
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
     push_up(root) ;
}

void update(int l , int r , int L , int R , int root){
     if(color[root])
        return ;
     if(L == R){
         sum[root] = LL (sqrt(sum[root])) ;
         color[root] = sum[root] == 1 ;
         return ;
     }
     int mid = (L + R) >> 1 ;
     if(l <= mid)
        update(l , r , L , mid , root<<1) ;
     if(r > mid)
        update(l , r , mid+1 , R , root<<1|1) ;
     push_up(root) ;
}

LL query(int l , int r , int L , int R , int root){
   if(l <= L && R <= r)
     return  sum[root] ;
   int mid = (L + R) >> 1 ;
   LL ans = 0 ;
   if(l <= mid)
      ans += query(l , r , L , mid , root<<1) ;
   if(r > mid)
      ans += query(l , r , mid+1 , R , root<<1|1) ;
   return ans ;
}

int main(){
    int n , i , q , k = 1 , t , l , r;
    while(cin>>n){
        printf("Case #%d:\n" , k++) ;
        for(i = 1 ; i <= n ; i++)
            scanf("%I64d",&x[i]) ;
        make_tree(1 , n , 1) ;
        scanf("%d",&q) ;
        while(q--){
            scanf("%d%d%d",&t,&l,&r) ;
            if(l > r)
              swap(l , r) ;   
            if(t)
              printf("%I64d\n",query(l , r , 1 , n , 1)) ;
            else
              update(l , r , 1 , n , 1) ;
        }
        puts("") ;
    }
    return 0 ;
}

http://codeforces.com/problemset/problem/292/E   (区间更新)  

题目大意:两个数组,a和b,两种操作:

1:将数组a的区间[x,x+k-1]复制给数组b的区间[y,y+k-1]。

2:问当前b[x]的值。

const int  Max_N = 100008 ;
int  Pos[Max_N<<2] ; //区间左端映射到数组A下标的起点

void push_down(int root , int L , int R){
     if(Pos[root]){
        int mid = (L + R) >> 1 ;
        Pos[root<<1] = Pos[root] ;
        Pos[root<<1|1] = mid + 1 + Pos[root] - L ;
        Pos[root] = 0 ;
     }
}

void  make_tree(int L , int R , int root){
      Pos[root] = 0 ;
      if(L == R)
        return ;
      int mid = (L + R) >> 1 ;
      make_tree(L , mid , root<<1) ;
      make_tree(mid+1 , R , root<<1|1) ;
}

void update(int l , int r , int start , int L , int R , int root){
     if(l == L && R == r){
          Pos[root] = start ;
          return ;
     }
     push_down(root , L , R) ;
     int mid = (L + R) >> 1 ;
     if(r <= mid)
        update(l , r , start , L , mid , root<<1) ;
     else if(l > mid)
        update(l , r , start , mid+1 , R , root<<1|1) ;
     else{
        update(l , mid , start , L , mid , root<<1) ;
        update(mid+1 , r , start+mid+1-l , mid+1 , R ,root<<1|1) ;
     }
}

int query(int id , int L , int R , int root){
    if(L == R)
      return Pos[root] ;
    push_down(root , L , R) ;
    int mid = (L + R) >> 1 ;
    if(id <= mid)
       return query(id , L , mid , root<<1) ;
    else
       return query(id , mid+1 , R , root<<1|1) ;
}

int A[Max_N] , B[Max_N] ;
int  main(){
     int i ,t , n , m , x , y , k;
     cin>>n>>m ;
     for(i = 1 ; i <= n ; i++)
        scanf("%d" , &A[i]) ;
     for(i = 1 ; i <= n ; i++)
        scanf("%d" , &B[i]) ;
     make_tree(1 , n , 1) ;
     while(m--){
          scanf("%d%d" , &t , &x) ;
          if(t == 1){
               scanf("%d%d" , &y , &k) ;
               update(y , y+k-1 , x , 1 , n , 1) ;
          }
          else{
               int id = query(x , 1 , n , 1) ;
               printf("%d\n" , id ? A[id] : B[x]) ;
          }
     }
     return 0 ;
}

染色问题,题目1496:数列区间

题目描述:
接下来我们会对其进行m(1<=m<=100000)次操作,每次操作都会将区间[l,r]内的所有数字都变为一个特定的数字,并且每次操作这个特定的数字都不相同。
我们可以简单的认为,第一次操作时将给定区间内的数字都变为1,第二次将给定区间内数字都变为2,第三次变为3,以此类推。
在经过m次操作完成后,要求输出该数列中,拥有相同正整数(不包括0)的最长连续区间长度。
若n = 5,m = 3,原数列00000
第一次操作区间[1,3],
数列变为11100
第二次操作区间[3,4],
数列变为11220
第三次操作区间[3,5]
数列变为11333
则最长连续区间为[3,5]拥有共同正整数3,故输出其长度3。
输入:
接下去m行,每行两个整数l,r,表示该次操作区间为[l,r]。(1<=l<=r<=n)
输出:
样例输入:

5 3
1 3
3 4
3 5
5 2
1 3
1 5
样例输出:
3
5
区间更新;
lazy标记

const int Max_N = 1000008 ;
int color[Max_N<<2]  , final_color[Max_N] ;

void push_down(int root){
     if(color[root]){
         color[root<<1] = color[root<<1|1] = color[root] ;
         color[root] = 0 ;
     }
}

void make_tree(int L , int R , int root){
     color[root] = 0 ;
     if(L == R)
        return ;
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
}

void update(int l , int r , int c , int L , int R , int root){
     if(l <= L && R <= r){
         color[root] = c ;
         return ;
     }
     push_down(root) ;
     int mid = (L + R) >> 1 ;
     if(l <= mid)
        update(l , r , c , L , mid , root<<1) ;
     if(r > mid)
        update(l , r , c , mid+1 , R , root<<1|1) ;
}

void query(int L , int R , int root){
     if(L == R){
        final_color[L] = color[root] ;
        return ;
     }
     push_down(root) ;
     int mid = (L + R) >> 1 ;
     query(L , mid , root<<1) ;
     query(mid+1 , R , root<<1|1) ;
}

int Ans(int N){
    int ans = 0 ;
    int now = final_color[1] , num = 1 ;
    for(int i = 2 ; i <= N ; i++){
       if(final_color[i] == now)
            num++ ;
       else{
           if(now)
             ans = max(ans , num) ;
           now = final_color[i] ;
           num = 1 ;
       }
    }
    if(now)
       ans = max(ans , num) ;
    return ans ;
}

int main(){
    int n , m  , i , l , r;
    while(scanf("%d%d" , &n ,&m) != EOF){
        make_tree(1 , n , 1) ;
        for(i = 1 ; i <= m ; i++){
            scanf("%d%d" , &l , &r) ;
            if(l > r)
               swap(l , r) ;
            update(l , r , i , 1 , n , 1) ;
        }
        query(1 , n , 1) ;
        printf("%d\n" , Ans(n)) ;
    }
    return 0 ;
}

POJ 3667 Hotel 区间合并

输入 2 a b:将[a,a+b-1]的房间清空
思路:记录区间中最长的空房间

输入 1 a:询问是不是有连续长度为a的空房间,有的话住进最左边

const int Max_N = 55558 ;
int l_can[Max_N<<2] , r_can[Max_N<<2] , all_can[Max_N<<2] , color[Max_N<<2] ;

void make_tree(int L , int R , int root){
     l_can[root] = r_can[root] = all_can[root] = R - L + 1 ;
     color[root] = -1 ;
     if(L == R)
        return ;
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
}

void push_down(int L , int R , int root){
     if(color[root] != -1){
          color[root<<1] = color[root<<1|1] = color[root] ;
          int mid = (L + R) >> 1 ;
          l_can[root<<1]   = r_can[root<<1]   = all_can[root<<1]   = (color[root] ? mid-L+1 : 0)  ;
          l_can[root<<1|1] = r_can[root<<1|1] = all_can[root<<1|1] = (color[root] ? R - mid : 0) ;
          color[root] = -1 ;
     }
}

void push_up(int L , int R , int root){
     l_can[root] = l_can[root<<1] ;
     r_can[root] = r_can[root<<1|1] ;
     int mid = (L + R) >> 1 ;
     if(l_can[root] == mid - L + 1)
        l_can[root] += l_can[root<<1|1] ;
     if(r_can[root] == R - mid)
        r_can[root] += r_can[root<<1] ;
     all_can[root] = max(max(all_can[root<<1] , all_can[root<<1|1]) ,
                         r_can[root<<1] + l_can[root<<1|1]) ;
}

void update(int l , int r , int c , int L , int R , int root){
     if(l <= L && R <= r){
          l_can[root] = r_can[root] = all_can[root] = (c? R-L+1 : 0) ;
          color[root] = c ;
          return ;
     }
     push_down(L , R , root) ;
     int mid = (L + R) >> 1 ;
     if(l <= mid)
         update(l , r ,c , L , mid , root<<1) ;
     if(r > mid)
         update(l , r ,c , mid+1 , R , root<<1|1) ;
     push_up(L , R , root) ;
}

int query(int len , int  L , int R , int root){
    if(L == R)
        return L ;
    push_down(L , R , root) ;
    int mid = (L + R) >> 1 ;
    if(len <= all_can[root<<1])
        return query(len , L , mid , root<<1) ;
    else if(len <= r_can[root<<1]+ l_can[root<<1|1])
        return mid - r_can[root<<1] + 1 ;
    else
        return query(len , mid+1 , R , root<<1|1) ;
}

int main(){
    int n , m , k , x , y , id ;
    scanf("%d%d" ,&n , &m) ;
    make_tree(1 , n , 1) ;
        while(m--){
            scanf("%d%d" ,&k ,&x) ;
            if(k == 1){
                if(all_can[1] < x)
                   puts("0") ;
                else{
                   id = query(x , 1 , n , 1) ;
                   printf("%d\n" ,id) ;
                   update(id , id + x -1 , 0 , 1 , n , 1) ;
                }
            }
            else{
                scanf("%d" , &y) ;
                update(x , x+y-1 , 1 , 1 , n , 1) ;
            }
        }
    return 0 ;
}



 

http://codeforces.com/problemset/problem/46/D  (区间合并)

题目大意:
有一条长度为L的街道,有N个操作,操作有两种:
(1)"1 a",表示有一辆长度为a的车开进来想找停车位;
停车位必须满足与它前面的车距离至少为b,与后面的车距离至少为f;
如果能找到这样的停车位;输出这辆车的起始位置(且这个位置最小),否则输出-1;
(2)"2 a",表示第a个事件里进来停车的那辆车开出去了;

算法思想:
建立起点为-b,终点为L+f的线段树;
查找的时候,直接查找len+b+f的线段就可以了;

注意这里存的是坐标点个数,而不是线段长度。

 1 //节点个数
 2 const int Max_N = 100300 ;
 3 int  L_canuse[Max_N<<2] , R_canuse[Max_N<<2] , All_canuse[Max_N<<2]  , color[Max_N<<2] ;
 4 
 5 void make_tree(int L , int R , int root){
 6      L_canuse[root] = R_canuse[root] = All_canuse[root] = R - L + 1 ;
 7      color[root] = -1 ;
 8      if(L == R)
 9         return ;
10      int mid = (L + R) >> 1 ;
11      make_tree(L , mid , root<<1) ;
12      make_tree(mid+1 , R , root<<1|1) ;
13 }
14 
15 void push_up(int root , int L , int R){
16      L_canuse[root] = L_canuse[root<<1] ;
17      R_canuse[root] = R_canuse[root<<1|1] ;
18      int mid = (L + R) >> 1 ;
19      if(L_canuse[root] == mid - L + 1)
20         L_canuse[root] += L_canuse[root<<1|1] ;
21      if(R_canuse[root] == R - mid)
22         R_canuse[root] += R_canuse[root<<1] ;
23      All_canuse[root] = max(max(All_canuse[root<<1] , All_canuse[root<<1|1]),
24                             R_canuse[root<<1] + L_canuse[root<<1|1]) ;
25 }
26 
27 void push_down(int root , int L , int R){
28      if(color[root] != -1){
29            color[root<<1] = color[root<<1|1] = color[root] ;
30            int mid = (L + R) >> 1 ;
31            L_canuse[root<<1] = R_canuse[root<<1] = All_canuse[root<<1] = (color[root]? mid - L + 1 : 0) ;
32            L_canuse[root<<1|1] = R_canuse[root<<1|1] = All_canuse[root<<1|1] = (color[root]? R - mid : 0) ;
33            color[root] = -1 ;
34      }
35 }
36 
37 void update(int l , int r , int c , int L , int R , int root){
38      if(l <= L && R <= r){
39            L_canuse[root] = R_canuse[root] = All_canuse[root] = (c? R - L + 1 : 0) ;
40            color[root] = c ;
41            return ;
42      }
43      push_down(root , L , R) ;
44      int mid = (L + R) >> 1 ;
45      if(l <= mid)
46         update(l , r , c , L , mid , root<<1) ;
47      if(r > mid)
48         update(l , r , c , mid+1 , R , root<<1|1) ;
49      push_up(root , L , R) ;
50 }
51 
52 int  query(int x , int L , int R , int root){
53      if(L == R)
54         return L  ;
55      push_down(root , L , R) ;
56      int mid = (L + R) >> 1 ;
57      if(x <= All_canuse[root<<1])
58         return query(x , L , mid , root<<1) ;
59      else if(x <= R_canuse[root<<1] + L_canuse[root<<1|1])
60         return mid - R_canuse[root<<1] + 1 ;
61      else
62         return query(x , mid+1 , R , root<<1|1) ;
63 }
64 
65 struct Car{
66        int Start  ;
67        int Len ;
68 }car[108];
69 
70 int  main(){
71      int n ,L , B , F , t  , x ;
72      cin>>L>>B>>F;
73      make_tree(-B , L+F , 1) ;
74      cin>>n ;
75      for(int i = 1 ; i <= n ; i++){
76         cin>>t>>x ;
77         if(t == 1){
78             car[i].Len = x ;
79             if(All_canuse[1] < x + B + F + 1)
80                 puts("-1") ;
81             else{
82                 car[i].Start = query(x+B+F , -B , L+F  , 1) + B ;
83                 update(car[i].Start , car[i].Start + car[i].Len - 1, 0 , -B , L+F , 1) ;
84                 printf("%d\n",car[i].Start) ;
85              }
86         }
87         else
88             update(car[x].Start , car[x].Start + car[x].Len - 1 , 1 , -B , L+F , 1) ;
89      }
90      return 0 ;
91 }

 

 

 

 

 

hdu 1504  (区间合并)

Tunnel Warfare

Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 3609    Accepted Submission(s): 1377


Problem Description
During the War of Resistance Against Japan, tunnel warfare was carried out extensively in the vast areas of north China Plain. Generally speaking, villages connected by tunnels lay in a line. Except the two at the ends, every village was directly connected with two neighboring ones.

Frequently the invaders launched attack on some of the villages and destroyed the parts of tunnels in them. The Eighth Route Army commanders requested the latest connection state of the tunnels and villages. If some villages are severely isolated, restoration of connection must be done immediately!
 

 

Input
The first line of the input contains two positive integers n and m (n, m ≤ 50,000) indicating the number of villages and events. Each of the next m lines describes an event.

There are three different events described in different format shown below:

D x: The x-th village was destroyed.

Q x: The Army commands requested the number of villages that x-th village was directly or indirectly connected with including itself.

R: The village destroyed last was rebuilt.
 

 

Output
Output the answer to each of the Army commanders’ request in order on a separate line.
 

 

Sample Input
7 9D 3D 6D 5Q 4Q 5RQ 4RQ 4
 Sample Output
1024
/*区间合并*/
typedef long long LL ;
const int Max_N = 50100 ;
 /*Left[i] ,到节点i左端点连续村庄的个数 ,Right[i] ,到节点i右端点连续村庄的个数 */
int Left[Max_N<<2] , Right[Max_N<<2] ;
void push_up(int L , int R , int root){
     Left[root] = Left[root<<1] ;
     Right[root] = Right[root<<1|1] ;
     int mid = (L + R) >> 1 ;
     if(Left[root] == mid - L + 1)
        Left[root] += Left[root<<1|1] ;
     if(Right[root] == R - mid)
        Right[root] += Right[root<<1] ;
}

void make_tree(int L ,int R ,int root){
     Left[root] = Right[root] = R - L + 1 ;
     if(L == R)
       return  ;
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
}

void update(int id , int type , int L , int R , int root){
     if(L == R){
        Left[root] = Right[root] = type ;
        return ;
     }
     int mid = (L + R) >> 1 ;
     if(id <= mid)
        update(id , type , L , mid , root<<1) ;
     else
        update(id , type , mid + 1 , R ,root<<1|1) ;
     push_up(L , R , root) ;
}

int query(int id , int L , int R , int root){
    if(L == R)
       return Left[root] ;
    int mid = (L + R) >> 1 ;
    if(id <= mid){
        if(Left[root<<1] == mid - L + 1)
             return Left[root<<1] + Left[root<<1|1] ;
        else if(L + Left[root<<1] > id)
             return Left[root<<1] ;
        else if(id > mid - Right[root<<1])
             return Right[root<<1] + Left[root<<1|1] ;
        else
             return query(id , L , mid , root<<1) ;
    }
    else{
        if(Right[root<<1|1] == R - mid)
             return Right[root<<1|1] + Right[root<<1] ;
        else if(id > R - Right[root<<1|1])
             return Right[root<<1|1] ;
        else if(mid + 1 + Left[root<<1|1] > id)
             return Right[root<<1] + Left[root<<1|1] ;
        else
             return query(id , mid+1 , R , root<<1|1) ;
    }
}

int main(){
    int n , m  , id ;
    stack<int> me ;
    char str[2] ;
    while(cin>>n>>m){
         while(!me.empty())
            me.pop() ;
         make_tree(1,n,1) ;
         while(m--){
               scanf("%s" , str) ;
               if(str[0] == 'D'){
                  scanf("%d",&id) ;
                  update(id , 0 , 1 , n , 1) ;
                  me.push(id) ;
               }
               else if(str[0] == 'R'){
                    if(!me.empty()){
                        update(me.top() , 1 , 1 , n , 1) ;
                        me.pop() ;
                    }
               }
               else{
                   scanf("%d",&id) ;
                   printf("%d\n",query(id,1,n,1)) ;
               }
         }
    }
    return 0 ;
}
题目1496:数列区间
题目描述:

有一段长度为n(1<=n<=1000000)的数列,数列中的数字从左至右从1到n编号。初始时数列中的数字都是0。
接下来我们会对其进行m(1<=m<=100000)次操作,每次操作都会将区间[l,r]内的所有数字都变为一个特定的数字,并且每次操作这个特定的数字都不相同。
我们可以简单的认为,第一次操作时将给定区间内的数字都变为1,第二次将给定区间内数字都变为2,第三次变为3,以此类推。
在经过m次操作完成后,要求输出该数列中,拥有相同正整数(不包括0)的最长连续区间长度。
若n = 5,m = 3,原数列00000
第一次操作区间[1,3],
数列变为11100
第二次操作区间[3,4],
数列变为11220
第三次操作区间[3,5]
数列变为11333
则最长连续区间为[3,5]拥有共同正整数3,故输出其长度3。

输入:

输入包含多组测试数据,每组测试数据第一行为两个整数n,m。
接下去m行,每行两个整数l,r,表示该次操作区间为[l,r]。(1<=l<=r<=n)

输出:

对于每组测试数据输出为一个整数,表示拥有相同正整数(不包括0)的最长连续区间长度。

样例输入:
5 3
1 3
3 4
3 5
5 2
1 3
1 5
样例输出:
3
5
区间更新;
lazy标记。

const int Max_N = 1000008 ;
int color[Max_N<<2]  , final_color[Max_N] ;

void push_down(int root){
     if(color[root]){
         color[root<<1] = color[root<<1|1] = color[root] ;
         color[root] = 0 ;
     }
}

void make_tree(int L , int R , int root){
     color[root] = 0 ;
     if(L == R)
        return ;
     int mid = (L + R) >> 1 ;
     make_tree(L , mid , root<<1) ;
     make_tree(mid+1 , R , root<<1|1) ;
}

void update(int l , int r , int c , int L , int R , int root){
     if(l <= L && R <= r){
         color[root] = c ;
         return ;
     }
     push_down(root) ;
     int mid = (L + R) >> 1 ;
     if(l <= mid)
        update(l , r , c , L , mid , root<<1) ;
     if(r > mid)
        update(l , r , c , mid+1 , R , root<<1|1) ;
}

void query(int L , int R , int root){
     if(L == R){
        final_color[L] = color[root] ;
        return ;
     }
     push_down(root) ;
     int mid = (L + R) >> 1 ;
     query(L , mid , root<<1) ;
     query(mid+1 , R , root<<1|1) ;
}

int Ans(int N){
    int ans = 0 ;
    int now = final_color[1] , num = 1 ;
    for(int i = 2 ; i <= N ; i++){
       if(final_color[i] == now)
            num++ ;
       else{
           if(now)
             ans = max(ans , num) ;
           now = final_color[i] ;
           num = 1 ;
       }
    }
    if(now)
       ans = max(ans , num) ;
    return ans ;
}

int main(){
    int n , m  , i , l , r;
    while(scanf("%d%d" , &n ,&m) != EOF){
        make_tree(1 , n , 1) ;
        for(i = 1 ; i <= m ; i++){
            scanf("%d%d" , &l , &r) ;
            if(l > r)
               swap(l , r) ;
            update(l , r , i , 1 , n , 1) ;
        }
        query(1 , n , 1) ;
        printf("%d\n" , Ans(n)) ;
    }
    return 0 ;
}

Hdu 4514

(1)"1 x y c",代表 把区间 [x,y] 上的值全部加c

(2)"2 x y c",代表 把区间 [x,y] 上的值全部乘以c

(3)"3 x y c" 代表 把区间 [x,y]上的值全部赋值为c

(4)"4 x y p" 代表 求区间 [x,y] 上值的p次方和1<=p<=3

const int Max_N = 100008  ;
const int Mod = 10007 ;

void   ADD(int &x , int y){
       x  = ( x + y ) % Mod ;
}

struct Node{
       int  L , R  ;
       int  sum[4];
       int  mult , add ;
       int  Len(){
            return  R - L + 1 ;
       }
       int  Mid(){
            return (L + R) >> 1 ;
       }
       void  Init(int l , int r){
            L = l ;
            R = r ;
            sum[1] = sum[2] = sum[3] = 0 ;
            mult = 1 ;
            add  = 0 ;
       }
       void  DoMult(int x){
            sum[1] = sum[1] * x % Mod ;
            sum[2] = sum[2] * x % Mod * x % Mod ;
            sum[3] = sum[3] * x % Mod * x % Mod * x % Mod ;
            mult   = mult * x % Mod ;
            add    = add  * x % Mod ;
       }
       void  DoAdd(int x){
            ADD(sum[3] , 3 * x * sum[2] % Mod) ;
            ADD(sum[3] , 3 * x * x % Mod * sum[1]) ;
            ADD(sum[3] , x * x % Mod * x % Mod * Len()) ;
            ADD(sum[2] , sum[1] * 2 * x % Mod) ;
            ADD(sum[2] , x * x % Mod * Len() % Mod) ;
            ADD(sum[1] , x * Len() % Mod) ;
            ADD(add , x) ;
       }

} ;

Node seg[Max_N << 2] ;

void push_up(int root){
     for(int i = 1 ; i <= 3 ; i++){
          seg[root].sum[i] = (seg[root<<1].sum[i] + seg[root<<1|1].sum[i]) % Mod ;
     }
}

void push_down(int root){
     seg[root<<1].DoMult(seg[root].mult) ;
     seg[root<<1].DoAdd(seg[root].add) ;
     seg[root<<1|1].DoMult(seg[root].mult) ;
     seg[root<<1|1].DoAdd(seg[root].add) ;
     seg[root].mult = 1 ;
     seg[root].add  = 0 ;
}


void make_tree(int root , int L , int R){
     seg[root].Init(L , R) ;
     if(L == R)
        return ;
     int mid = (L + R) >> 1 ;
     make_tree(root<<1 , L , mid) ;
     make_tree(root<<1|1 , mid+1 , R) ;
     push_up(root) ;
}

void update(int root , int L , int R , int _mult , int _add){
     if(seg[root].L == L  && seg[root].R == R){
           seg[root].DoMult(_mult) ;
           seg[root].DoAdd(_add) ;
           return ;
     }
     push_down(root) ;
     int mid = seg[root].Mid() ;
     if(R <= mid)
         update(root<<1 , L , R , _mult , _add)  ;
     else if(L > mid)
         update(root<<1|1 , L , R , _mult , _add)  ;
     else{
         update(root<<1 ,   L , mid , _mult , _add)  ;
         update(root<<1|1 , mid+1 , R , _mult , _add)  ;
     }
     push_up(root) ;
}

int  query(int root , int L , int R , int type){
     if(seg[root].L == L && seg[root].R == R)
        return seg[root].sum[type] ;
     push_down(root) ;
     int mid = seg[root].Mid() ;
     int ans = 0 ;
     if(R <= mid)
         return query(root<<1 , L , R , type)  ;
     else if(L > mid)
         return query(root<<1|1 , L , R , type) ;
     else
         return (query(root<<1 , L , mid , type) + query(root<<1|1 , mid+1 , R , type) ) % Mod;
}

int  main(){
     int n , m , k , l , r , c;
     while(scanf("%d%d" ,&n ,&m)){
          if(n == 0 && m == 0)
             break  ;
          make_tree(1 , 1 , n) ;
          while(m--){
              scanf("%d%d%d%d" ,&k , &l , &r , &c) ;
              if(k == 1)
                  update(1 , l , r , 1 , c) ;
              else if(k == 2)
                  update(1 , l , r , c , 0) ;
              else if(k == 3)
                  update(1 , l , r , 0 , c) ;
              else
                  printf("%d\n" ,query(1 , l , r , c)) ;
          }
     }
     return 0 ;
}

HDU  4288  给出一个有序集合,3种操作。插入一个数,删除一个数,都保证序列有序。以及求和  , 其中求和是将下标%5==3的所有数求和


const  int Max_N = 100008 ;
int    sum[Max_N<<2] ;
LL     ans[Max_N<<2][5] ;
int    x[Max_N]  ,  query[Max_N] ;
char   opt[Max_N][8] ;

void   up(int t){
       for(int i = 0 ; i < 5 ; i++)
          ans[t][i] = ans[t<<1][i] + ans[t<<1|1][(i-sum[t<<1]%5 + 5)%5] ;
}

void   make(int L , int R , int t){
       memset(ans[t] , 0 , sizeof(ans[t])) ;
       sum[t] = 0 ;
       if(L == R) return  ;
       int M = (L + R) >> 1 ;
       make(L , M , t<<1) ;
       make(M+1 , R ,t<<1|1) ;
}

void   update(int i , int g , int L , int R , int t){
       sum[t] += (g==0? -1 : 1) ;
       if(L == R){
            ans[t][0] = (LL)(g*x[i]) ;
            return ;
       }
       int M = (L + R) >> 1 ;
       if(i <= M)  update(i , g , L , M , t<<1) ;
       else   update(i , g , M+1 ,R , t<<1|1) ;
       up(t) ;
}

int  main(){
     int  i , n , t , pos ;
     while(scanf("%d" ,&n) != EOF){
          t = 0 ;
          for(i = 1 ; i <= n ; i++){
               scanf("%s" , opt[i]) ;
               if(opt[i][0] == 'a' || opt[i][0] == 'd'){
                      scanf("%d" ,&query[i]) ;
                      x[t++] = query[i] ;
               }
          }
          sort(x , x+t) ;
          t =  unique(x , x + t) - x ;
          make(0 , t-1 , 1) ;
          for(i = 1 ; i <= n ; i++){
              if(opt[i][0] == 's')  printf("%I64d\n" ,ans[1][2]) ;
              else{
                   pos = lower_bound(x , x+t , query[i]) - x ;
                   if(opt[i][0] == 'a')  update(pos , 1 , 0 , t-1 , 1) ;
                   else                  update(pos , 0 , 0 , t-1 , 1) ;
              }
          }
     }
     return 0 ;
}

给n个数,两种操作1:U  a b   更新第a个为b (从0开始)2: Q    a ,b  查询 a,b之间LCIS(最长连续递增子序列)的长度。


const  int  maxn = 100008 ;
int    lmax[maxn<<2] , rmax[maxn<<2] , amax[maxn<<2] ;
int    x[maxn] ;

void  up(int t , int L , int R){
      lmax[t] = lmax[t<<1] ;
      rmax[t] = rmax[t<<1|1]  ;
      amax[t] = max(amax[t<<1] , amax[t<<1|1]) ;
      int M = (L + R) >> 1 ;
      if(x[M] < x[M+1]){
            if(lmax[t] == M - L + 1)  lmax[t] += lmax[t<<1|1] ;
            if(rmax[t] == R - M)      rmax[t] += rmax[t<<1] ;
            amax[t] = max(amax[t] , rmax[t<<1] + lmax[t<<1|1]) ;
      }
}

void   make(int L , int R , int t){
       if(L == R){
           lmax[t] = rmax[t] = amax[t] = 1 ;
           return  ;
       }
       int M = (L + R) >> 1  ;
       make(L , M , t<<1) ;
       make(M+1, R , t<<1|1) ;
       up(t , L , R) ;
}

void update(int i , int L , int R , int t){
     if(L == R) return  ;
     int M = (L + R) >> 1 ;
     if(i <= M) update(i , L , M , t<<1) ;
     else       update(i , M+1 , R , t<<1|1) ;
     up(t , L , R) ;
}

int  ask(int l , int r , int L , int R , int t){
     if(l <= L && R <= r) return amax[t] ;
     int M = (L + R) >> 1 ;
     if(r <= M) return ask(l , r , L , M , t<<1) ;
     if(l > M)  return ask(l , r , M+1 , R , t<<1|1) ;
     int s = max( ask(l , r , L , M , t<<1) , ask(l , r , M+1 , R , t<<1|1) ) ;
     if(x[M] < x[M+1])
          s = max(s  ,  min(rmax[t<<1] , M-l+1) +  min(lmax[t<<1|1] , r-M) ) ;
     return s ;
}

int    main(){
       int i , n , t , m  , id  , a , b ;
       char s[2] ;
       cin>>t ;
       while(t--){
            scanf("%d%d" ,&n ,&m) ;
            for(i = 1 ; i <= n ; i++) scanf("%d" ,&x[i]) ;
            make(1 , n , 1) ;
            id = 0 ;
            while(m--){
                 scanf("%s%d%d" ,s , &a , &b) ;
                 if(s[0] == 'U'){
                      x[++a] = b ;
                      update(a , 1 , n , 1) ;
                 }
                 else{
                     a++ , b++ ;
                     printf("%d\n" , ask(a , b , 1 , n , 1)) ;
                 }
            }
       }
       return 0 ;
}

给n个数,两种操作1:U  a b  c 更新[a , b] + c , 2: Q    a ,b  查询 a,b之间LCIS(最长连续递增子序列)的长度。

const  int  maxn = 100008 ;
int    lmax[maxn<<2] , rmax[maxn<<2] , amax[maxn<<2] ;
int    x[maxn] , add[maxn<<2] , lx[maxn<<2] , rx[maxn<<2] ;

void  up(int t , int L , int R){
      lx[t] = lx[t<<1] ;
      rx[t] = rx[t<<1|1] ;
      lmax[t] = lmax[t<<1] ;
      rmax[t] = rmax[t<<1|1]  ;
      amax[t] = max(amax[t<<1] , amax[t<<1|1]) ;
      int M = (L + R) >> 1 ;
      if(rx[t<<1] < lx[t<<1|1]){
            if(lmax[t] == M - L + 1)  lmax[t] += lmax[t<<1|1] ;
            if(rmax[t] == R - M)      rmax[t] += rmax[t<<1] ;
            amax[t] = max(amax[t] , rmax[t<<1] + lmax[t<<1|1]) ;
      }
}

void  down(int t){
      if(add[t]){
           add[t<<1] += add[t] ;
           add[t<<1|1] += add[t] ;
           lx[t<<1] += add[t] ;
           rx[t<<1] += add[t] ;
           lx[t<<1|1] += add[t] ;
           rx[t<<1|1] += add[t] ;
           add[t] = 0 ;
      }
}

void   make(int L , int R , int t){
       add[t] = 0  ;
       if(L == R){
           lmax[t] = rmax[t] = amax[t] = 1 ;
           lx[t] = x[L] ;
           rx[t] = x[L] ;
           return  ;
       }
       int M = (L + R) >> 1  ;
       make(L , M , t<<1) ;
       make(M+1, R , t<<1|1) ;
       up(t , L , R) ;
}

void update(int l , int r , int a , int L , int R , int t){
     if(l <= L && R <= r){
             add[t] += a ;
             lx[t]  += a ;
             rx[t]  += a ;
             return  ;
     }
     down(t) ;
     int M = (L + R) >> 1 ;
     if(l <= M) update(l ,r , a , L , M , t<<1) ;
     if(r > M)  update(l ,r , a , M+1 , R , t<<1|1) ;
     up(t , L , R) ;
}

int  ask(int l , int r , int L , int R , int t){
     if(l <= L && R <= r) return amax[t] ;
     int M = (L + R) >> 1 ;
     if(r <= M) return ask(l , r , L , M , t<<1) ;
     if(l > M)  return ask(l , r , M+1 , R , t<<1|1) ;
     int s = max( ask(l , r , L , M , t<<1) , ask(l , r , M+1 , R , t<<1|1) ) ;
     if(rx[t<<1] < lx[t<<1|1])
          s = max(s  ,  min(rmax[t<<1] , M-l+1) +  min(lmax[t<<1|1] , r-M) ) ;
     return s ;
}

int    main(){
       int i , n , t , m  , id  , a , b , c , T = 1 ;
       char s[2] ;
       cin>>t ;
       while(t--){
            scanf("%d%d" ,&n ,&m) ;
            printf("Case #%d:\n" ,T++) ;
            for(i = 1 ; i <= n ; i++) scanf("%d" ,&x[i]) ;
            make(1 , n , 1) ;
            id = 0 ;
            while(m--){
                 scanf("%s" ,s) ;
                 if(s[0] == 'a'){
                      scanf("%d%d%d" ,&a ,&b ,&c) ;
                      update(a , b ,c , 1 ,n , 1) ;
                 }
                 else{
                     scanf("%d%d" ,&a ,&b) ;
                     printf("%d\n" , ask(a , b , 1 , n , 1)) ;
                 }
            }
       }
       return 0 ;
}

0 l r表示查询区间[l,r]的最长的连续的1的个数,1 l r表示将区间[l,r]所有的数异或1(0->1 ,1->0)

const  int  maxn = 100008 ;
int    preb[maxn<<2] , sufb[maxn<<2] , mxb[maxn<<2] ;
int    prew[maxn<<2] , sufw[maxn<<2] , mxw[maxn<<2] ;
int    color[maxn<<2] ;

void   up(int t , int L , int R){
       int  M = (L + R) >> 1 ;
       preb[t] = preb[t<<1] ;
       sufb[t] = sufb[t<<1|1] ;
       if(preb[t] == M-L+1) preb[t] += preb[t<<1|1] ;
       if(sufb[t] == R-M)   sufb[t] += sufb[t<<1] ;

       prew[t] = prew[t<<1] ;
       sufw[t] = sufw[t<<1|1] ;
       if(prew[t] == M-L+1) prew[t] += prew[t<<1|1] ;
       if(sufw[t] == R-M)   sufw[t] += sufw[t<<1] ;

       mxb[t] = max(mxb[t<<1] , mxb[t<<1|1]) ;
       mxb[t] = max(mxb[t] , sufb[t<<1] + preb[t<<1|1]) ;

       mxw[t] = max(mxw[t<<1] , mxw[t<<1|1]) ;
       mxw[t] = max(mxw[t] , sufw[t<<1] + prew[t<<1|1]) ;
}

void  change(int t){
      swap(preb[t] , prew[t]) ;
      swap(sufb[t] , sufw[t]) ;
      swap(mxb[t] , mxw[t]) ;
}

void  down(int t){
      if(color[t]){
           change(t<<1) ; change(t<<1|1) ;
           color[t<<1] ^= 1 ;
           color[t<<1|1] ^= 1 ;
           color[t] = 0 ;
      }
}

void  make(int L , int R , int t){
      color[t] = 0 ;
      if(L == R){
          int x ; scanf("%d" ,&x) ;
          if(x == 1){
               preb[t] = sufb[t] = mxb[t] = 1 ;
               prew[t] = sufw[t] = mxw[t] = 0 ;
          }
          else{
              preb[t] = sufb[t] = mxb[t] = 0 ;
              prew[t] = sufw[t] = mxw[t] = 1 ;
          }
          return ;
      }
      int M = (L + R) >> 1 ;
      make(L , M , t<<1) ;
      make(M+1 , R , t<<1|1) ;
      up(t , L , R) ;
}

void  update(int l , int r , int L , int R , int t){
      if(l <= L && R <= r){
            change(t) ;
            color[t] ^= 1 ;
            return ;
      }
      down(t) ;
      int M = (L + R) >> 1 ;
      if(l <= M)  update(l , r , L , M , t<<1) ;
      if(r > M)   update(l , r , M+1 , R , t<<1|1) ;
      up(t , L , R) ;
}

int  ask(int l , int r , int L , int R , int t){
     if(l <= L && R <= r)  return mxb[t] ;
     down(t) ;
     int M = (L + R) >> 1 ;
     if(r <= M)  return ask(l , r , L , M , t<<1) ;
     if(l > M)   return ask(l , r , M+1 , R , t<<1|1) ;
     int s = max( ask(l , r , L , M , t<<1)  ,  ask(l , r , M+1 , R , t<<1|1) ) ;
     s = max(s , min(sufb[t<<1] , M-l+1) + min(preb[t<<1|1] , r-M) ) ;
     return s  ;
}

int  main(){
     int n , i , m , k , a , b ;
     while(scanf("%d" ,&n) != EOF){
          make(1 , n , 1) ;
          scanf("%d" ,&m) ;
          while(m--){
               scanf("%d%d%d" ,&k , &a ,&b) ;
               if(k) update(a , b , 1 , n , 1) ;
               else  printf("%d\n" , ask(a , b , 1 , n , 1)) ;
          }
     }
     return 0 ;
}

在墙上贴海报[L, R], 海报可以互相覆盖,问最后可以看见几张不同的海报(离散化)

const  int  maxn = 10008 ;
int    color[maxn<<4] ;
set<int> st ;

void   down(int t){
       if(color[t] != -1){
             color[t<<1] = color[t<<1|1] = color[t] ;
             color[t] = -1  ;
       }
}

void   update(int l , int r , int c , int L , int R , int t){
       if(l <= L && R <= r){
              color[t] = c ;
              return ;
       }
       down(t)  ;
       int M = (L + R) >> 1 ;
       if(l <= M) update(l , r , c , L , M , t<<1) ;
       if(r > M)  update(l , r , c , M+1, R , t<<1|1) ;
}

int    sum ;
void   query(int L , int R , int t){
       if(color[t] != -1){
              if(st.find(color[t]) == st.end()){
                  sum++ ;
                  st.insert(color[t]) ;
              }
              return  ;
       }
       if(L == R)  return  ;
       int M = (L + R) >> 1 ;
       query(L , M , t<<1) ;
       query(M+1 , R , t<<1|1) ;
}

int    x[maxn<<2] , li[maxn] , ri[maxn] ;
int    main(){
       int t  , n , m , i , k  , l ,  r ;
       cin>>t  ;
       while(t--){
            scanf("%d" ,&n) ;
            memset(color , -1 , sizeof(color)) ;
            k = 0 ;
            for(i = 1 ; i <= n  ; i++){
                 scanf("%d%d" ,&li[i] , &ri[i]) ;
                 x[k++] = li[i] ;
                 x[k++] = ri[i] ;
            }
            sort(x , x+k) ;
            k = unique(x , x+k) - x ;
            for(i = k-1 ; i > 0 ; i--){
                if(x[i] != x[i-1] + 1) x[k++] = x[i-1] + 1 ;
            }
            sort(x , x+k) ;
            for(i = 1 ; i <= n ; i++){
                 l = lower_bound(x , x+k , li[i]) - x ;
                 r = lower_bound(x , x+k , ri[i]) - x ;
                 update(l , r , i , 0 , k-1 , 1) ;
            }
            st.clear() ; sum = 0 ;
            query(0 , k-1 , 1) ;
            printf("%d\n" , sum) ;
       }
       return 0 ;
}

n小球,初始时,所有的小球为黑色,然后就给出N次染色,每次染色是对[l ,r]全部染成white或black,最后要求出最长的white,给出其起点和终点球的编号。(离散化)

const  int  maxn = 2008 ;
int    color[maxn<<4] ;


void   down(int t){
       if(color[t] != -1){
             color[t<<1] = color[t<<1|1] = color[t] ;
             color[t] = -1  ;
       }
}

void   make(int L , int R , int t){
       color[t] = -1 ;
       if(L == R){
             color[t] = 0 ;
             return  ;
       }
       int M = (L + R) >> 1 ;
       make(L , M , t<<1) ;
       make(M+1 , R , t<<1|1) ;
}

void   update(int l , int r , int c , int L , int R , int t){
       if(l <= L && R <= r){
              color[t] = c ;
              return ;
       }
       down(t)  ;
       int M = (L + R) >> 1 ;
       if(l <= M) update(l , r , c , L , M , t<<1) ;
       if(r > M)  update(l , r , c , M+1, R , t<<1|1) ;
}

int    vis[maxn<<2] ;
void   query(int L , int R , int t){
       if(color[t] == 1){
              for(int i = L ; i <= R ; i++)  vis[i] = 1 ;
              return  ;
       }
       if(L == R)  return  ;
       if(color[t] == -1){
           int M = (L + R) >> 1 ;
           query(L , M , t<<1) ;
           query(M+1 , R , t<<1|1) ;
       }
}

int    x[maxn<<2] , li[maxn] , ri[maxn] , co[maxn];

int    main(){
       int   n  , i ,j , k  , l ,  r  , st , ed ;
       char s[2] ;;
       while(cin>>n){
            k = 0 ;
            for(i = 1 ; i <= n  ; i++){
                 scanf("%d%d%s" ,&li[i] , &ri[i] , s) ;
                 x[k++] = li[i] ;
                 x[k++] = ri[i] ;
                 if(s[0] == 'w') co[i] = 1 ;
                 else            co[i] = 0 ;
            }
            sort(x , x+k) ;
            k = unique(x , x+k) - x ;
            for(i = k-1 ; i > 0 ; i--){
                if(x[i] != x[i-1] + 1) x[k++] = x[i-1] + 1 ;
            }
            sort(x , x+k) ;
            make(0 , k-1 , 1) ;
            for(i = 1 ; i <= n ; i++){
                 l = lower_bound(x , x+k , li[i]) - x ;
                 r = lower_bound(x , x+k , ri[i]) - x ;
                 update(l , r , co[i] , 0 , k-1 , 1) ;
            }
            memset(vis , 0 , sizeof(vis)) ;
            query(0 , k-1 , 1) ;
            st = -1 ; ed = -2 ;
            x[k] = x[k-1] + 1 ;
            for(i = 0  ; i < k ; i++){
                 if(vis[i]){
                      for(j = i ; j < k && vis[j] ; j++) ;
                      j-- ;
                      if(ed - st < x[j+1]-1 - x[i]){
                           st = x[i] ;
                           ed = x[j+1] - 1  ;
                      }
                      i = j ;
                 }
            }
            if(st == -1) puts("Oh, my god") ;
            else         printf("%d %d\n" , st , ed) ;
       }
       return 0 ;
}

给出一棵树,做 M 次操作,每次要么将一棵子树上每个结点的布尔值取反,要么查询一棵子树上布尔值为 true 的个数

先 dfs 将树转化成一个序列(求出每个结点的先序遍历值,以及它的所有子节点中的最大先序遍历值,以这两个值作为该结点在序列上的区间左右端点),然后用线段树维护,区间修改/区间查询,非常经典了

const  int maxn = 100008 ;
vector<int> g[maxn] ;
int   lock  , sd[maxn] , td[maxn] ;
void  dfs(int u){
      sd[u] = ++lock ;
      for(int i = 0 ; i < g[u].size() ; i++){
          dfs(g[u][i]) ;
      }
      td[u] = lock ;
}

int   sum[maxn<<2] , color[maxn<<2] ;

void  down(int t , int L , int R){
      if(color[t]){
           color[t<<1] ^= 1 ;
           color[t<<1|1] ^= 1 ;
           color[t] = 0 ;
           int M = (L + R) >> 1 ;
           sum[t<<1] = (M-L+1) - sum[t<<1] ;
           sum[t<<1|1] = (R-M) - sum[t<<1|1] ;
      }
}

void  up(int t){
      sum[t] = sum[t<<1] + sum[t<<1|1] ;
}

void  update(int l , int r , int L , int R , int t){
      if(l <= L && R <= r){
             sum[t] = (R-L+1) - sum[t] ;
             color[t] ^= 1 ;
             return  ;
      }
      down(t , L , R) ;
      int  M = (L + R) >> 1 ;
      if(l <= M) update(l , r , L , M , t<<1) ;
      if(r > M)  update(l , r , M+1 , R , t<<1|1) ;
      up(t) ;
}

int  ask(int l , int r , int L , int R , int t){
     if(l <= L && R <= r)  return sum[t] ;
     down(t , L , R) ;
     int s = 0 , M = (L + R) >> 1 ;
     if(l <= M) s += ask(l , r , L , M , t<<1) ;
     if(r > M)  s += ask(l , r , M+1 , R , t<<1|1) ;
     return s ;
}

int  main(){
     int n , m , i , x  ;
     char s[2] ;
     while(cin>>n>>m){
          for(i = 1 ; i <= n ; i++) g[i].clear() ;
          for(i = 2 ; i <= n ; i++){
              scanf("%d" ,&x)  ;
              g[x].push_back(i) ;
          }
          lock = 0 ;
          dfs(1) ;
          memset(sum , 0 , sizeof(sum)) ;
          memset(color , 0 , sizeof(color)) ;
          while(m--){
               scanf("%s%d" ,s ,&i) ;
               if(s[0] == 'o') update(sd[i],td[i],1,n,1) ;
               else printf("%d\n" , ask(sd[i],td[i],1,n,1)) ;
          }
          puts("") ; 
     }
     return 0 ;
}











你可能感兴趣的:(线段树专题)