zoukankan      html  css  js  c++  java
  • 牛客练习赛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 ;
    }
    
    
  • 相关阅读:
    三菱Q系列PLC MC协议通讯
    相机常用属性配置简介[转]---Labview IMAQ 修改相机曝光等参数的方法
    数码显微镜的实际放大倍数的正确计算方法【转载】
    VS2012 C# 配置log4net
    CHM格式帮助文档无法打开的问题
    win10 下安装win7虚拟机
    杂记:使用RawCap和Wireshark对 127.0.0.1或localhost 进行抓包
    杂记:01
    linux应用编程一:文件IO和目录操作
    QTableWidget常用函数及注意事项
  • 原文地址:https://www.cnblogs.com/Isaunoya/p/11660407.html
Copyright © 2011-2022 走看看