Saya percaya waktu logaritmik untuk semua pertanyaan dapat dicapai. Gagasan utamanya adalah menggunakan pohon interval, di mana setiap node di pohon sesuai dengan interval indeks. Saya akan membangun ide-ide kunci dengan memulai dengan versi yang lebih sederhana dari struktur data (yang dapat mendukung pengaturan dan bukan operasi lainnya), kemudian menambahkan fitur untuk mendukung fitur-fitur lainnya juga.
Skema sederhana (mendukung dapatkan dan atur, tetapi tidak menambah atau menusuk)
Katakanlah bahwa interval adalah datar jika fungsi f adalah konstan pada [ a , b ] , yaitu, jika f ( a ) = f ( a + 1 ) = ⋯ = f ( b ) .[a,b]f[a,b]f(a)=f(a+1)=⋯=f(b)
Struktur data sederhana kami akan menjadi pohon interval. Dengan kata lain, kita memiliki pohon biner, di mana setiap node bersesuaian dengan interval (indeks). Kami akan menyimpan interval di setiap simpul v pohon. Setiap daun akan sesuai dengan interval datar, dan mereka akan diatur sehingga membacakan daun kiri-ke-kanan memberi kita urutan interval datar berturut-turut yang terpisah dan yang penyatuan semua [ 1 , n ] . Interval untuk simpul internal adalah penyatuan interval kedua anaknya. Juga, di setiap simpul daun ℓ kami akan menyimpan nilai V ( ℓ )I(v)v[1,n]ℓV(ℓ)dari fungsi pada interval I ( ℓ ) yang sesuai dengan simpul ini (perhatikan bahwa interval ini datar, sehingga f konstan pada interval tersebut, jadi kami hanya menyimpan nilai tunggal f di setiap simpul daun).fI(ℓ)ff
Secara ekuivalen, Anda dapat membayangkan bahwa kita mempartisi ke dalam interval datar, dan kemudian struktur data adalah pohon pencarian biner di mana kunci adalah titik akhir kiri dari interval tersebut. Daun mengandung nilai f pada beberapa rentang indeks di mana f adalah konstan.[1,n]ff
Gunakan metode standar untuk memastikan bahwa pohon biner tetap seimbang, yaitu kedalamannya adalah (di mana m menghitung jumlah daun saat ini di pohon). Tentu saja, m ≤ n , jadi kedalaman selalu paling banyak O ( lg n ) . Ini akan sangat membantu di bawah ini.O(lgm)mm≤nO(lgn)
Kami sekarang dapat mendukung operasi get dan set sebagai berikut:
mudah: kita melintasi pohon untuk menemukan daun yang intervalnya berisi i . Ini pada dasarnya hanya melintasi pohon pencarian biner. Karena kedalamannya adalah O ( lg n ) , waktu lari adalah O ( lg n ) .get(i)iO(lgn)O(lgn)
lebih rumit. Ini berfungsi seperti ini:set([a,b],y)
Pertama, kami menemukan interval daun mengandung a ; jika a 0 < a , maka kita membagi interval daun ini menjadi dua interval [ a 0 , a - 1 ] dan [ a , b 0 ] (sehingga mengubah simpul daun ini menjadi simpul internal dan memperkenalkan dua anak).[a0,b0]aa0<a[a0,a−1][a,b0]
Selanjutnya, kami menemukan interval daun mengandung b ; jika b < b 1 , kami membagi interval daun ini menjadi dua interval [ a 1 , b ] dan [ b + 1 , b 1 ] (sehingga mengubah simpul daun ini menjadi simpul internal dan memperkenalkan dua anak).[a1,b1]bb<b1[a1,b][b+1,b1]
Pada titik ini, saya mengklaim bahwa interval dapat dinyatakan sebagai penyatuan terpisah dari interval O ( lg n ) yang sesuai dengan beberapa subset dari simpul O ( lg n ) di pohon. Jadi, hapus semua turunan dari simpul tersebut (ubah menjadi daun) dan tetapkan nilai yang disimpan di simpul tersebut menjadi y .[a,b]O(lgn)O(lgn)y
Akhirnya, karena kami memodifikasi bentuk pohon, kami akan melakukan rotasi yang diperlukan untuk menyeimbangkan kembali pohon (menggunakan teknik standar apa pun untuk menjaga keseimbangan pohon).
O(lgn)O(lgn)O(lgn)
O(lgn)O(lgmin(n,s))s
Menambahkan dukungan untuk tambah
Kami dapat memodifikasi struktur data di atas sehingga juga dapat mendukung operasi penambahan. Secara khusus, alih-alih menyimpan nilai fungsi dalam daun, itu akan direpresentasikan sebagai jumlah angka yang disimpan dalam satu set node.
f(i)iivV(v)v0,v1,…,vkvkI(vk)V(v0)+⋯+V(vk)
xx
add([a,b],δ)[a,b]O(lgn)O(lgn)δO(lgn)node. (Kami tidak menghapus keturunan mereka.)
O(lgn)O(lgmin(n,s))s
Mendukung operasi penikaman
Permintaan penusukan adalah yang paling menantang untuk didukung. Gagasan dasarnya adalah mengubah struktur data di atas untuk mempertahankan invarian tambahan berikut:
I(ℓ)ℓ
[a,b][a,b][a,b]a′,b′1≤a′≤a≤b≤b′≤n[a′,b′]=[a,b][a′,b′]
Ini membuat operasi tusukan mudah diimplementasikan:
ff12=O(1)O(lgn)
O(lgn)O(lgmin(n,s))s
Berpisah pikiran
Fiuh, ini skema yang cukup rumit. Saya harap saya tidak membuat kesalahan. Silakan periksa pekerjaan saya dengan cermat sebelum mengandalkan solusi ini.
add
akan linear dalam jumlah subinterval meskipun; Pernahkah Anda berpikir tentang pohon hamparan dengan simpul " + δ " tambahan yang belum dipadatkan, dipadatkan dengan malas?