HDU 6070題解 二分 線段樹

2022-03-29 10:38:15 字數 3376 閱讀 2143

傳送門

此題的題意不是很清晰,要注意的一點是在區間[l,r]中,預設題目編號最後一次出現的時候是ac的

比如1 2 1 2 3 ,在區間[1,4]中,第3次提交時ac第1題,第4次提交時ac第2題,故比例為2/4=0.5

所以此問題可以轉化為

給定乙個序列,定義區間[l,r]的值為cn

t(l,

r)r−

l+1' role="presentation" style="position: relative">cnt

(l,r

)r−l

+1cn

t(l,

r)r−

l+1,(cnt(l,r)為區間中不同元素的個數,求值最大的區間,輸出其最大值

1.二分答案

很明顯此題用直接列舉區間的方法會超時,必須使用二分來降低時間複雜度

如果二分區間端點,則答案不存在單調性,無法二分

因此二分答案,顯然答案可取的範圍是[0,1)

設二分中點為mid,由題意cn

t(l,

r)r−

l+1≤

mid' role="presentation" style="position: relative">cnt

(l,r

)r−l

+1≤m

idcn

t(l,

r)r−

l+1≤

mid ([l,r]為所有區間中值最小的區間)

兩邊同乘化簡r-l+1,移項,整理得cn

t(l,

r)+m

id×l

≤mid

×(r+

1)' role="presentation" style="position: relative">cnt

(l,r

)+mi

d×l≤

mid×

(r+1

)cnt

(l,r

)+mi

d×l≤

mid×

(r+1

)2.求不等式左邊的值,判斷mid是否可取到

對於每次二分,列舉r從1~n,對於每乙個r,我們再求右端點為r的所有區間的所有區間的值中的最小值

我們維護一棵線段樹,線段數的每個葉子節點l表示左端點為l,右端點為r(當前的列舉值)時的值,再統計區間[1,r]最小值

這樣我們就求出了右端點為r的所有區間的值中的最小值

由於r從1~n,線段樹中的值也在不斷變化,我們怎麼更新線段樹中的值呢?

每次r+1,需要更新[r,r]這個區間,區間加mi

d×r' role="presentation" style="position: relative">mid

×rmi

d×r,

再更新[x,r]各區間的cnt值,設a上一次出現的位置為last[a],則區間[last[a]+1,r]都需要+1,因為區間內出現了乙個新的數a,而對於last[a]之前的位置,由於a已經出現過,cnt值不受影響

時間複雜度分析:

二分時間複雜度為o(

log2

1ϵ)' role="presentation" style="position: relative">o(l

og21

ϵ)o(

log2

1ϵ),其中

ϵ' role="presentation" style="position: relative">ϵ

ϵ為精度,在此題中設ϵ=

10−5' role="presentation" style="position: relative">ϵ=10

−5ϵ=

10−5即可

線段樹的建樹時間複雜度為o(

nlog

2n)' role="presentation" style="position: relative">o(n

log2

n)o(

nlog

2n),n次插入與查詢時間複雜度為o(

nlog

2n)' role="presentation" style="position: relative">o(n

log2

n)o(

nlog

2n)

所以總的時間複雜度分析為o(

nlog

2n×l

og21

ϵ)' role="presentation" style="position: relative">o(n

log2

n×lo

g21ϵ

)o(n

log2

n×lo

g21ϵ

)

#include

#include

#include

#include

#define maxn 60005

#define eps 1e-5

#define inf 0x7fffffff

using

namespace

std;

int a[maxn];

int pos[maxn],last[maxn];

struct node

}tree[maxn<<2];

void push_up(int pos)

void build(int l,int r,int pos)

void push_down(int pos)

}void update(int l,int r,double v,int pos)

push_down(pos);

int mid=(l+r)>>1;

if(l<=mid) update(l,r,v,pos<<1);

if(r>mid) update(l,r,v,pos<<1|1);

push_up(pos);

}double query(int l,int r,int pos)

push_down(pos);

int mid=(l+r)>>1;

double ans=inf;

if(l<=mid) ans=min(ans,query(l,r,pos<<1));

if(r>mid) ans=min(ans,query(l,r,pos<<1|1));

return ans;

}int t,n;

int main()

for(int i=1;i<=n;i++)

double l=0,r=1;

double ans=inf;

while(fabs(l-r)>eps)

}if(is_min)

else l=mid;

}printf("%lf\n",ans);

}}

hdu6070 線段樹 二分

題意給你乙個區間,讓你找,區間種類數 區間長度最小是多少。思路先公式化簡 size r l 1 mid size l 1 mid r mid mid是二分的值 對於每乙個元素a i 他能影響的區間是,last a i 1 到i last表示這個這個元素上一次出現的位置 他能讓這個區間的種類數 1,由...

線段樹 二分 HDU6070

題目讓我們求type l,r r l 1 的最小,顯然可以用01分數規劃,來二分求最小答案。所以我們從左往右移動端點,來統計種類。線段樹來維護type l,r l mid的值。include using namespace std const int n 1e6 7 const double eps...

hdu 6070 二分答案 線段樹

題意 區間價值為 區間元素種類數 區間長度 問最小價值的區間是?思路 直接求解很困難,考慮二分答案判斷,注意這題的關鍵是將二分答案後的不等式進行變換,如官方題解。二分答案 mid,檢驗是否存在乙個區間滿足 size l,r r l 1 mid,也就是 size l,r mid l mid r 1 之...