• Codeforces 889F Letters Removing(二分 + 线段树 || 树状数组)


    Letters Removing

    题意:给你一个长度为n的字符串,然后进行m次删除操作,每次删除区间[l,r]内的某个字符,删除后并且将字符串往前补位,求删除完之后的字符串。

    题解:先开80个set 将每个字符对应的下标存入空间, 然后每次删除了一个字符之后就将字符串的相应位置改成一个不会产生干扰的字符(我这里使用的是'.')。 并且在线段树的相应位置标记一下。然后每次删除时候的左右区间就用2分区查找。

    找到位置pos 使得 [1,pos]的值等于 pos - l, 这样就可以找到相应的区间了。原因, [1,pos]的值代表着区间[1,pos]内被删除的元素个数是多少。 pos - 向左移动的数目([1,pos]) 就是在进行前面删除操作之后并往前补位的位置了。

     1 #include<set>
     2 #include<iostream>
     3 #include<string>
     4 using namespace std;
     5 #define lson l,m,rt<<1
     6 #define rson m+1,r,rt<<1|1
     7 const int N = 2e5+10;
     8 int n, m;
     9 int tree[N<<2];
    10 string str, tmp;
    11 set<int> G[80];
    12 void PushUp(int rt)
    13 {
    14     tree[rt] = tree[rt<<1|1] + tree[rt<<1];
    15 }
    16 void Revise(int L, int l, int r, int rt)
    17 {
    18     if(l == r)
    19     {
    20         tree[rt]++;
    21         return ;
    22     }
    23     int m = l+r >> 1;
    24     if(L <= m) Revise(L,lson);
    25     else Revise(L,rson);
    26     PushUp(rt);
    27 }
    28 int Query(int L, int R, int l, int r, int rt)
    29 {
    30     if(L <= l && r <= R)
    31         return tree[rt];
    32     int m = l+r >> 1;
    33     int ret = 0;
    34     if(L <=m) ret += Query(L,R,lson);
    35     if(m < R) ret+= Query(L,R,rson);
    36     return ret;
    37 }
    38 int Find_pos(int pos)
    39 {
    40     int l = pos, r = n;
    41     while(l <= r)
    42     {
    43         int m = l+r >> 1;
    44         int num = Query(1,m,1,n,1);
    45         if(m == num + pos && str[m] != '.')
    46         {
    47             return m;
    48         }
    49         else if(m < num+ pos) l = m+1;
    50         else r = m - 1;
    51     }
    52 }
    53 int main()
    54 {
    55     ios::sync_with_stdio(false);
    56     cin.tie(0);
    57     cout.tie(0);
    58     cin >> n >> m;
    59     cin >> str;
    60     set<int>::iterator it;
    61     str = "#"+str;//将字符串往右整体移动一位
    62     for(int i = 1; i <= n; i++)
    63         G[str[i]-'0'].insert(i);//将对应的位置分别存到对应的set
    64     int l, r;
    65     while(m--)
    66     {
    67         cin >> l >> r >> tmp;
    68         if(l + tree[1] > n) continue;   //如果区间左端点大于有效长度
    69         if(l == r) l = r = Find_pos(l); //那么就表示不用进行删除操作了
    70         else {
    71                 l = Find_pos(l);
    72                 if(r + tree[1] > n) r = n;
    73                 else r = Find_pos(r);
    74              }
    75         int pos =(int)tmp[0] - '0';
    76         it = G[pos].begin();
    77         while(it != G[pos].end())
    78         {
    79             int index = *it;
    80             if(index >= l && index <= r)
    81             {
    82                 Revise(index,1,n,1);
    83                 str[index] = '.';
    84                 it = G[pos].erase(it);
    85             }
    86             else it++;
    87             if(index > r) break;
    88         }
    89     }
    90     for(int i = 1; i <= n; i++)
    91     {
    92         if(str[i] != '.')
    93             cout << str[i];
    94     }
    95     cout << endl;
    96     return 0;
    97 }

    树状数组代码:

     1 #include<set>
     2 #include<iostream>
     3 #include<string>
     4 using namespace std;
     5 const int N = 2e5+10;
     6 int n, m;
     7 int tree[N];
     8 string str, tmp;
     9 set<int> G[80];
    10 int lowbit(int x)
    11 {
    12     return x&(-x);
    13 }
    14 void Add(int x)
    15 {
    16     while(x <= n)
    17     {
    18         tree[x]++;
    19         x += lowbit(x);
    20     }
    21 }
    22 int Query(int x)
    23 {
    24     int ret = 0;
    25     while(x > 0)
    26     {
    27         ret += tree[x];
    28         x -= lowbit(x);
    29     }
    30     return ret;
    31 }
    32 int Find_pos(int pos)
    33 {
    34     int l = pos, r = n;
    35     while(l <= r)
    36     {
    37         int m = l+r >> 1;
    38         int num = Query(m);
    39         if(m == num + pos && str[m] != '.')
    40         {
    41             return m;
    42         }
    43         else if(m < num+ pos) l = m+1;
    44         else r = m - 1;
    45     }
    46 }
    47 int main()
    48 {
    49     ios::sync_with_stdio(false);
    50     cin.tie(0);
    51     cout.tie(0);
    52     cin >> n >> m;
    53     cin >> str;
    54     set<int>::iterator it;
    55     str = "#"+str;//将字符串往右整体移动一位
    56     for(int i = 1; i <= n; i++)
    57         G[str[i]-'0'].insert(i);//将对应的位置分别存到对应的set
    58     int l, r;
    59     while(m--)
    60     {
    61         cin >> l >> r >> tmp;
    62         if(l + tree[1] > n) continue;  //如果区间左端点大于有效长度
    63         if(l == r) l = r = Find_pos(l);//那么就表示不用进行删除操作了
    64         else
    65         {
    66             l = Find_pos(l);
    67             if(r + tree[1] > n) r = n;
    68             else r = Find_pos(r);
    69         }
    70 
    71         int pos = tmp[0] - '0';
    72         it = G[pos].begin();
    73         while(it != G[pos].end())
    74         {
    75             int index = *it;
    76             if(index >= l && index <= r)
    77             {
    78                 Add(index);
    79                 str[index] = '.';
    80                 it = G[pos].erase(it);
    81             }
    82             else it++;
    83             if(index > r) break;
    84         }
    85     }
    86     for(int i = 1; i <= n; i++)
    87     {
    88         if(str[i] != '.')
    89             cout << str[i];
    90     }
    91     cout << endl;
    92     return 0;
    93 }
  • 相关阅读:
    用于 webpack 打包后方便修改的配置文件
    antd 中对树形表格中二级元素进行筛选过滤
    layui快速搭建一个后台管理系统
    centos使用shell定时清空缓存
    内存异常原因查询
    Protocol "‘https" not supported or disabled in libcurl
    HTML table标签实现表头固定
    vue 查询某个对象在对象列表的索引位置
    vue 实现页面监听键盘按键 上下左右
    Vue 实现图片监听鼠标滑轮滚动实现图片缩小放大功能
  • 原文地址:https://www.cnblogs.com/MingSD/p/8398053.html
Copyright © 2020-2023  润新知