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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程资源 > 编程问答 >内容正文

编程问答

[FJOI 2016]bzoj 4408 神秘数 - 线段树

發(fā)布時(shí)間:2023/12/14 编程问答 37 豆豆
生活随笔 收集整理的這篇文章主要介紹了 [FJOI 2016]bzoj 4408 神秘数 - 线段树 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

題目大意:給你一列數(shù),多次詢問(wèn)用一個(gè)區(qū)間的數(shù)字形成一個(gè)可重集合,最小的不能被表示為其一個(gè)子集的數(shù)字是多少。
題解:考慮給你一個(gè)可重集合你怎么算:從小到大排序,假設(shè)用前x個(gè)數(shù)字不能表示的最小都數(shù)字是ans,那么如果a[x+1]>ans,則ans就是答案,否則ans+=a[++x]。這個(gè)過(guò)程顯然可以線段樹(shù)每次區(qū)區(qū)間最小值,加上,然后把這個(gè)最小值設(shè)為INF,但是復(fù)雜度是不對(duì)的,例如全是1。但是發(fā)現(xiàn)這個(gè)過(guò)程顯然可以優(yōu)化:若當(dāng)前答案是ans,已經(jīng)加入了a[1…x],而a[(x+1)…y]<=ans,那么可以一口氣把a(bǔ)[(x+1)…y]加到ans上(此時(shí)ans=\sum_{i=1}^y a[i])。這樣做好像復(fù)雜度還是不靠譜?其實(shí)是對(duì)的,考慮一個(gè)數(shù)字x,再第i輪(此時(shí)答案記做ans[i])沒(méi)有被加入,而第i+1輪被加入了,意味著x>ans[i],而從第i輪到第i+2輪,ans至少翻了一倍。因此用主席樹(shù)維護(hù)上述過(guò)程,復(fù)雜度兩個(gè)log。

#include<iostream> #include<cstring> #include<cstdio> #include<algorithm> #include<vector> #define gc getchar() #define N 100010 #define pb push_back #define debug(x) cerr<<#x<<"="<<x #define sp <<" " #define ln <<endl using namespace std; inline int inn() {int x,ch;while((ch=gc)<'0'||ch>'9');x=ch^'0';while((ch=gc)>='0'&&ch<='9')x=(x<<1)+(x<<3)+(ch^'0');return x; } struct segment{int s;segment *ch[2]; }*T[N];int m,a[N];vector<int> v; inline int getid(int x) { return lower_bound(v.begin(),v.end(),x)-v.begin()+1; } int build(segment* &rt,int l,int r) {rt=new segment,rt->s=0;if(l==r) return 0;int mid=(l+r)>>1;return build(rt->ch[0],l,mid),build(rt->ch[1],mid+1,r),0; } int update(segment* &x,segment* &y,int l,int r,int p,int v) {x=new segment,x->s=y->s+v,x->ch[0]=y->ch[0],x->ch[1]=y->ch[1];if(l==r) return 0;int mid=(l+r)>>1;if(p<=mid) update(x->ch[0],y->ch[0],l,mid,p,v);if(mid<p) update(x->ch[1],y->ch[1],mid+1,r,p,v);return 0; } int query(segment* &rt,int l,int r,int s,int t) {if(s<=l&&r<=t) return rt->s;int mid=(l+r)>>1,ans=0;if(s<=mid) ans+=query(rt->ch[0],l,mid,s,t);if(mid<t) ans+=query(rt->ch[1],mid+1,r,s,t);return ans; } int query(int l,int r,int p) {int t=getid(p);if(v[t-1]>p) t--;if(!t) return 0;return query(T[r],1,m,1,t)-query(T[l-1],1,m,1,t); } int main() {int n=inn();for(int i=1;i<=n;i++) a[i]=inn(),v.pb(a[i]);sort(v.begin(),v.end());v.erase(unique(v.begin(),v.end()),v.end());m=(int)v.size();build(T[0],1,m);for(int i=1;i<=n;i++)update(T[i],T[i-1],1,m,getid(a[i]),a[i]);for(int q=inn();q;q--){int l=inn(),r=inn(),ans=0,t;while(ans<(t=query(l,r,ans+1))) ans=t;printf("%d\n",ans+1);}return 0; }

總結(jié)

以上是生活随笔為你收集整理的[FJOI 2016]bzoj 4408 神秘数 - 线段树的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。