日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

【bzoj4408】[Fjoi 2016]神秘数 主席树

發布時間:2025/4/9 编程问答 25 豆豆
生活随笔 收集整理的這篇文章主要介紹了 【bzoj4408】[Fjoi 2016]神秘数 主席树 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

題目描述

一個可重復數字集合S的神秘數定義為最小的不能被S的子集的和表示的正整數。例如S={1,1,1,4,13},
1 = 1
2 = 1+1
3 = 1+1+1
4 = 4
5 = 4+1
6 = 4+1+1
7 = 4+1+1+1
8無法表示為集合S的子集的和,故集合S的神秘數為8。
現給定n個正整數a[1]..a[n],m個詢問,每次詢問給定一個區間[l,r](l<=r),求由a[l],a[l+1],…,a[r]所構成的可重復數字集合的神秘數。

輸入

第一行一個整數n,表示數字個數。
第二行n個整數,從1編號。
第三行一個整數m,表示詢問個數。
以下m行,每行一對整數l,r,表示一個詢問。

輸出

對于每個詢問,輸出一行對應的答案。

樣例輸入

5
1 2 4 9 10
5
1 1
1 2
1 3
1 4
1 5

樣例輸出

2
4
8
8
8


題解

主席樹的一道神題

我們先想暴力怎么做:把一段區間的數取出來,排個序,從小到大選擇。如果$a1$~$a_{i-1}$能夠表示$1~x$,此時加入$a_i$,如果$a_i\le x+1$,那么就可以表示$x+a_i$,否則x就是答案。

試著優化一下這個過程:設$a_{i-1}=k$,$a_i=y$,1~i-1的神秘數為ans=x+1,那么顯然$ans=\sum\limits_{t=1}^{i-1}a_t$。此時如果存在k+1~ans的數就可以更新ans。更具體地,如果k+1~ans內的數的和為s,那么ans+=s;而ans為1~k的數的和+1,故ans的新值應該賦為1~ans的數的和。

說了這么多廢話有什么用?我們可以發現每次ans的增量都大于等于前一次的ans,所以這個過程的時間復雜度應該為$O(\log a)$。

而事實上我們并不能把區間拿出來排序,所以需要使用數據結構,上一個主席樹就好了。

時間復雜度為$O(n\log^2n)$

#include <cstdio> #include <algorithm> #define N 100010 using namespace std; int v[N] , a[N] , root[N] , ls[N << 5] , rs[N << 5] , sum[N << 5] , tot; void insert(int p , int l , int r , int x , int &y) {y = ++tot , sum[y] = sum[x] + a[p];if(l == r) return;int mid = (l + r) >> 1;if(p <= mid) rs[y] = rs[x] , insert(p , l , mid , ls[x] , ls[y]);else ls[y] = ls[x] , insert(p , mid + 1 , r , rs[x] , rs[y]); } int query(int p , int l , int r , int x , int y) {if(r <= p) return sum[y] - sum[x];int mid = (l + r) >> 1;if(p <= mid) return query(p , l , mid , ls[x] , ls[y]);else return query(p , mid + 1 , r , rs[x] , rs[y]) + sum[ls[y]] - sum[ls[x]]; } int main() {int n , m , i , x , y , ans , tmp;scanf("%d" , &n);for(i = 1 ; i <= n ; i ++ ) scanf("%d" , &a[i]) , v[i] = a[i];sort(a + 1 , a + n + 1);for(i = 1 ; i <= n ; i ++ ) v[i] = lower_bound(a + 1 , a + n + 1 , v[i]) - a;for(i = 1 ; i <= n ; i ++ ) insert(v[i] , 1 , n , root[i - 1] , root[i]);a[n + 1] = 1 << 30;scanf("%d" , &m);while(m -- ){scanf("%d%d" , &x , &y) , ans = 1;while((tmp = query(upper_bound(a + 1 , a + n + 2 , ans) - a - 1 , 1 , n , root[x - 1] , root[y])) >= ans)ans = tmp + 1;printf("%d\n" , ans);}return 0; }

?

?

轉載于:https://www.cnblogs.com/GXZlegend/p/7115254.html

總結

以上是生活随笔為你收集整理的【bzoj4408】[Fjoi 2016]神秘数 主席树的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。