problem
這題的題意大概是
給出一段長度為\(n\) 的區間
\(q\)次詢問求 \(l\)~ \(r\) 這個區間內 最短的一段區間 \(l\)~\(r\)
使得 \(\oplus_^ a_j= 0\)
\(l<=l
誒 離線麼?樹狀陣列好像不好做啊 因為大多數人只會單點修改區間修改和差分吧
考慮離線+線段樹
我們先記錄乙個 \(sum_i = \oplus_^i a_j\)
那麼我們用乙個類似桶一樣的東西 \(pos_i\) 記錄上乙個出現\(sum_i\) 的位置
顯然這題是個單點修改 求區間最小值
考慮移動 右指標 \(r\)
把詢問的右端點為\(r\) 的存在一起 這樣就省下來乙個排序
我們要記錄 \(l\) 點對區間的貢獻
應該反過來做 考慮 \(sum_j\) 最後一次出現的位置 \(pos_\)
然後對 \(pos_\) 進行單點修改 能保證這個肯定對於\(pos_\)這個點來說向右偏移最小的值使得異或和為0
因為移動的是右端點 右端點往右的區間和當前區間是互為獨立的 或者換句話說 右端點往右的區間對當前區間是沒有貢獻的即對答案不會影響
然後直接大力查詢 \(query(l,r)\) 就可以了
#includeusing 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)
inline void change(int x , int l , int r , int rt , int val)
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)
#define fi first
#define se second
signed main()
for(register int i = 1 ; i <= q ; i ++) ) ;
} build(1 , n , 1) ;
for(register int i = 1 ; i <= n ; i ++)
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 ;
}
牛客練習賽53 老瞎眼 pk 小鮮肉 線段樹思維
傳送門 給定長度為n nn的陣列,q qq個詢問 每次問 l,r l,r l,r 內最小的區間長度 l,r l,r l,r 使得al al 1 ar 0 a l oplus a oplus a 0 al al 1 a r 0 明顯需要預處理 如果做乙個異或字首和pre x pre x pre x 那...
牛客練習賽53 ABC
a 簡單dp include define ll long long using namespace std const ll mod 1e9 7 ll d 1000000 2 ll n intmain cout d n 1 d n 0 mod return0 b 分塊 include define...
牛客練習賽53 B, C, E 題解
b 美味果凍 更換一下列舉順序得到 容易發現 i 為 j,2j 2j,3j t 1 j,t j 時後面向下取整的結果是一樣的,分塊計算即可,j 次冪通過 j 1 次冪 o 1 得到,時間複雜度為 o nlogn include using namespace std typedef long lon...