zoukankan      html  css  js  c++  java
  • Codeforces 899F Letters Removing 线段树/树状数组

      虽然每次给一个区间,但是可以看作在区间内进行数个点操作,同样数列下标是动态变化的,如果我们将每个字符出现看作1,被删除看作0,则通过统计前缀和就能轻松计算出两个端点的位置了!这正是经典的树状数组操作

    需要注意的是,即使每次找到了两个端点,如果只是朴素总左到右遍历会TLE,所以可以给每个字符开一个set,每个set储存字符出现的位置。

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <cstring>
      4 #include <string>
      5 #include <map>
      6 #include <set>
      7 #include <vector>
      8 #include <algorithm>
      9 #pragma warning ( disable : 4996 )
     10 using namespace std;
     11 
     12 int Max( int a, int b ) { return a>b?a:b; }
     13 int Min( int a, int b ) { return a>b?b:a; }
     14 int lowbit( int x )        { return x&-x; }
     15 
     16 const int inf = 0x3f3f3f3f;
     17 const int maxn = 2e5+5;
     18 
     19 set<int> pos[65];
     20 set<int>::iterator it, it2;
     21 char str[maxn];
     22 int istr[maxn];
     23 bool isdel[maxn];
     24 
     25 int len, q;
     26 
     27 int getI( char c )
     28 {
     29     if( c >= 'a' && c <= 'z' ) return c-'a';
     30     if( c >= 'A' && c <= 'Z' ) return c-'A'+26;
     31     if( c >= '0' && c <= '9' ) return c-'0'+52;
     32 }
     33 
     34 int sum( int x )
     35 {
     36     int ret = 0;
     37     while( x > 0 )
     38         {    ret += istr[x]; x -= lowbit(x); }
     39     return ret;
     40 }
     41 
     42 void add( int x, int d )
     43 {
     44     while( x <= len )
     45         { istr[x] += d; x += lowbit(x); }
     46 }
     47 
     48 int find( int s )
     49 {
     50     int mid, lhs = 1, rhs = len;
     51     int tmp;
     52     while ( lhs <= rhs )
     53     {
     54         mid = (lhs+rhs)>>1;
     55         tmp = sum(mid);
     56         if ( tmp >= s ) rhs = mid-1;
     57         else lhs = mid+1;
     58     }
     59     return lhs;
     60 }
     61 
     62 void change( int l, int r, char c )
     63 {
     64     int p = getI(c);
     65     it = pos[p].lower_bound(l);
     66     while ( it!=pos[p].end() && *it<=r )
     67     {
     68         isdel[(*it)] = true;
     69         add((*it), -1);
     70         it2 = it; it++;
     71         pos[p].erase(it2);
     72     }
     73 }
     74 
     75 int main()
     76 {
     77     cin >> len >> q;
     78     scanf("%s", str+1);
     79 
     80     for ( int i = 1; i <= len; i++ )
     81     {
     82         add(i,1);
     83         int p = getI(str[i]);
     84         pos[p].insert(i);
     85     }
     86 
     87     int x, y;
     88     char c;
     89     for ( int i = 1; i <= q; i++ )
     90     {
     91         scanf( "%d %d %c", &x, &y, &c );
     92         x = find(x); y = find(y);
     93         change( x, y, c );
     94     }
     95 
     96     for( int i = 1; i <= len; i++ )
     97         if( !isdel[i] )
     98             printf( "%c", str[i] );
     99     
    100     printf("
    ");
    101     return 0;
    102 }
    View Code

     我们看到区间操作,自然就会想到线段树,但是数列下标是动态变换的,乍一看似乎线段树就没有用武之地了。实际仔细想想,线段树也可以动态统计从哪个区间开始操作,相比普通线段树只是在每次操作前要计算新的下标到哪了,实际上每个节点管辖的范围是始终不变的,变的只是范围内字符的个数size,每次操作前通过这个size找到对应的左端点和右端点就行了。

      1 //线段树
      2 #include <iostream>
      3 #include <cstdio>
      4 #include <cstring>
      5 #include <string>
      6 #include <map>
      7 #include <vector>
      8 #include <algorithm>
      9 #pragma warning ( disable : 4996 )
     10 using namespace std;
     11 
     12 int Max( int a, int b ) { return a>b?a:b; }
     13 int Min( int a, int b ) { return a>b?b:a; }
     14 
     15 const int inf = 0x3f3f3f3f;
     16 const int maxn = 2e5+2;
     17 
     18 struct tree {
     19     int size, lhs, rhs;
     20     int clu[62];
     21 }t[maxn<<2];
     22 char str[maxn];
     23 
     24 int getI( char c )
     25 {
     26     if( c >= 'a' && c <= 'z' ) return c-'a';
     27     if( c >= 'A' && c <= 'Z' ) return c-'A'+26;
     28     if( c >= '0' && c <= '9' ) return c-'0'+52;
     29 }
     30 
     31 char getC( int i )
     32 {
     33     if( i >= 0 && i <= 25 )  return 'a'+i;
     34     if( i >= 26 && i <= 51 ) return 'A'+i-26;
     35     if( i >= 52 && i <= 61 ) return '0'+i-52;
     36 }
     37 
     38 void pushUp( int index )
     39 {
     40     t[index].size = t[index<<1].size + t[index<<1|1].size;
     41     for ( int i = 0; i < 62; i++ )
     42         t[index].clu[i] = t[index<<1].clu[i] + t[index<<1|1].clu[i];
     43 }
     44 
     45 void build( int l, int r, int index )
     46 {
     47     t[index].lhs = l; t[index].rhs = r;
     48     if( l == r )
     49         { t[index].size = 1; t[index].clu[getI(str[l-1])] = 1; return; }
     50     int mid = (l+r)>>1;
     51     build(l, mid, index<<1);
     52     build(mid+1, r, index<<1|1);
     53     pushUp(index);
     54 }
     55 
     56 int find( int index, int x )
     57 {
     58     int l = t[index].lhs, r = t[index].rhs;
     59     if( l == r ) return l;
     60     if( t[index<<1].size >= x ) return find( index<<1, x );
     61     else return find( index<<1|1, x-t[index<<1].size );
     62 }
     63 
     64 void change( int index, int l, int r, int x ) 
     65 {
     66     int L = t[index].lhs, R = t[index].rhs;
     67     if ( r < L || l > R ) return;
     68     if ( !t[index].clu[x] ) return;
     69     if ( L == R ) { t[index].size--; t[index].clu[x]--; return; }
     70     change( index<<1, l, r, x );
     71     change( index<<1|1, l, r, x );
     72     t[index].size = t[index<<1].size + t[index<<1|1].size;
     73     t[index].clu[x] = t[index<<1].clu[x] + t[index<<1|1].clu[x];
     74 }
     75 
     76 void print( int i )
     77 {
     78     int L=t[i].lhs,R=t[i].rhs;
     79     if ( L==R )
     80     {
     81         for ( int j = 0; j < 62; j++ )
     82             if ( t[i].clu[j] ) printf("%c",getC(j));
     83         return;
     84     }
     85     print(i<<1);
     86     print(i<<1|1);
     87 
     88 }
     89 
     90 int main()
     91 {
     92     int len, q;
     93     cin >> len >> q;
     94     scanf("%s", str);
     95     build(1, len, 1);
     96 
     97     int x, y;
     98     char c;
     99     for ( int i = 1; i <= q; i++ )
    100     {
    101         scanf( "%d %d %c", &x, &y, &c );
    102         int l = find( 1, x );
    103         int r = find( 1, y );
    104         change( 1, l, r, getI(c) );
    105     }
    106     print(1);
    107     printf("
    ");
    108     return 0;
    109 }
    View Code
  • 相关阅读:
    顺序容器的操作
    C++顺序容器
    Java8实战系列一
    Java枚举的小知识点
    Java集合框架入门介绍(一)
    测试代码格式
    Eclipse通过jdbc连接sqlserver2008数据库的两种方式
    排序算法之插入排序
    排序算法之冒泡排序
    容器扩容之分摊时间复杂度分析
  • 原文地址:https://www.cnblogs.com/chaoswr/p/8585765.html
Copyright © 2011-2022 走看看