牛客练习赛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\n" , ans[i] == INT_MAX ? -1 : ans[i]) ;
  return 0 ;
}

posted @ 2019-10-12 11:18  _Isaunoya  阅读(232)  评论(0编辑  收藏  举报