• 牛客练习赛53-E 老瞎眼 pk 小鲜肉


    Problem

    这题的题意大概是

    给出一段长度为(n) 的区间

    (q)次询问求 (L)~ (R) 这个区间内 最短的一段区间 (l)~(r)

    使得 (oplus_{i=l}^{r} a_j= 0)

    (L<=l<r<=r)

    诶 离线么?树状数组好像不好做啊 因为大多数人只会单点修改区间修改和差分吧

    考虑离线+线段树

    我们先记录一个 (sum_i = oplus_{j=1}^i a_j)

    那么我们用一个类似桶一样的东西 (pos_i) 记录上一个出现(sum_i) 的位置

    显然这题是个单点修改 求区间最小值

    考虑移动 右指针 (r)

    把询问的右端点为(r) 的存在一起 这样就省下来一个排序

    我们要记录 (l) 点对区间的贡献

    应该反过来做 考虑 (sum_j) 最后一次出现的位置 (pos_{sum_j})

    然后对 (pos_{sum_j}) 进行单点修改 能保证这个肯定对于(pos_{sum_j})这个点来说向右偏移最小的值使得异或和为0

    因为移动的是右端点 右端点往右的区间和当前区间是互为独立的 或者换句话说 右端点往右的区间对当前区间是没有贡献的即对答案不会影响

    然后直接大力查询 (query(l,r)) 就可以了

    #include<bits/stdc++.h>
    using namespace std ;
    
    int n , q ;
    const int N = 5e5 + 5 ;
    int sum[N] ;
    vector < pair < int  , int > > v[N] ;
    int mn[N << 2] ;
    int pos[N << 2] ;
    int used[N] ;
    int ans[N << 1] ;
    inline void build(int l , int r , int rt) {
      mn[rt] = INT_MAX ;
      if(l == r) return ;
      int mid = l + r >> 1 ;
      build(l , mid , rt << 1) ;
      build(mid + 1 , r , rt << 1 | 1) ;
    }
    inline void change(int x , int l , int r , int rt , int val) {
      if(l == r) { mn[rt] = val ; return ; }
      int mid = l + r >> 1 ;
      if(x <= mid) change(x , l , mid , rt << 1 , val) ;
      else change(x , mid + 1 , r , rt << 1 | 1 , val) ;
      mn[rt] = min(mn[rt << 1] , mn[rt << 1 | 1]) ;
    }
    inline int query(int a , int b , int l , int r , int rt) {
      if(a <= l && r <= b) return mn[rt] ;
      int mid = l + r >> 1 ;
      int ans = INT_MAX ;
      if(a <= mid) ans = min(ans , query(a , b , l , mid , rt << 1)) ;
      if(b > mid) ans = min(ans , query(a , b , mid + 1 , r , rt << 1 | 1 )) ;
      return ans ;
    }
    #define fi first
    #define se second
    signed main() {
      scanf("%d %d" , & n , & q) ;
      for(register int i = 1 ; i <= n ; i ++) {
        int x ; scanf("%d" , & x) ;
        sum[i] = sum[i - 1] ^ x ;
      }
      for(register int i = 1 ; i <= q ; i ++) {
        int l , r , id ; scanf("%d %d" , & l , & r) ; id = i ;
        v[r].push_back({l , id}) ;
      }
      build(1 , n , 1) ;
      for(register int i = 1 ; i <= n ; i ++) {
        pos[sum[i - 1]] = i ;
        int p = pos[sum[i]] ;
        if(p && ! used[p]) {
          change(p , 1 , n , 1 , i - p + 1) ;
          used[p] = 1 ;
        }
        for ( auto x : v[i] ) ans[x.se] = query(x.fi , i , 1 , n , 1) ;
      }
      for(register int i = 1 ; i <= q ; i ++) printf("%d
    " , ans[i] == INT_MAX ? -1 : ans[i]) ;
      return 0 ;
    }
    
    
  • 相关阅读:
    ITSM运维管理整理总结
    牙轮的三相电压
    Surpac 安装
    Ubuntu安装PostgreSql
    内网网速测试
    Linux下使用speedtest测速
    Ubuntu安装elasticsearch 8.x和Kibana
    防抖和节流
    VUE配置proxy代理、开发环境、测试环境、生产环境
    Windows Terminal ssh 远程 Linux 和使用 Git
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/11660407.html
Copyright © 2020-2023  润新知