一道線段樹練習題

2021-10-01 08:16:20 字數 3914 閱讀 8344

e9首先我們有乙個考慮列舉每個mex,計算其貢獻的想法.即有多少個區間的mex

mexme

x是我們當前列舉的這個值.

然後我們手畫一下圖,可以發現,乙個數如果想要成為乙個區間的mex

mexme

x,必須要這個區間已經出現了所有比它小的數.所以可以從小到大列舉mex

mexme

x,然後用r

rr陣列記錄對於乙個左端點,滿足條件的右端點最近的位置,這樣就能幫助我們確定之後的mex

mexme

x在哪些區間.

然後為了列舉時的速度較快,我們用set維護當前"有效"的左端點."有效"的定義是:在列舉到了某個mex

mexme

x後,有些位置的右端點是一樣的,我們維護這些位置中最靠前的乙個.並且只修改這個位置,但是這樣其他位置的mex

mexme

x值沒有變(它們實際也要變).注意到其他位置形成了乙個區間,所以我們想到用線段樹維護這個區間加和.那麼這些數要變化多少呢?我們用lala

la陣列記錄每個位置最後一次作為"有效"位置的mex值是多少,然後加上當前值-la[

i]la[i]

la[i

]就好了.然後我們還要額外記錄這個位置原本的la[

i]la[i]

la[i

],在最後的統計答案的時候減掉.(因為這部分位置原本被認為是另乙個mex並且被更新到線段樹中,我們需要在新一次更新中減去)

時間複雜度o(n

logn

)o(nlogn)

o(nlog

n)

#include

using

namespace std;

typedef

long

long ll;

const

int maxn=

1e6+5;

inline

intread()

while

(isdigit

(c))

return t*f;

}int type,n,a[maxn]

,q;vector<

int> alfa[maxn]

;struct nodeque[maxn]

;struct block};

//記錄操作

bool

cmp2

(block a,block b)

bool

cmp(node a,node b)

set<

int> s;

typedef set<

int>

::iterator it;

int la[maxn]

,r[maxn]

,tot;

it pos[maxn]

;vector b;

void

modify

(int x,

int y,

int val)

for(

int i=

1;i<=tot;i++

)s.erase

(pos[i]);

s.insert

(x);r[x]

=y;la[x]

=val;

}struct tree

inline

void

pushdown

(int rt,

int l,

int r)

void

modify

(int rt,

int l,

int r,

int x,

int y,ll val)

if(tag[rt]

)pushdown

(rt,l,r)

;int mid=

(l+r)

>>1;

if(x<=mid)

modify

(rt<<

1,l,mid,x,y,val);if

(y>mid)

modify

(rt<<1|

1,mid+

1,r,x,y,val)

;pushup

(rt);}

ll query

(int rt,

int l,

int r,

int x,

int y)

if(tag[rt]

)pushdown

(rt,l,r)

;int mid=

(l+r)

>>1;

ll ans=0;

if(x<=mid)ans+

=query

(rt<<

1,l,mid,x,y);if

(y>mid)ans+

=query

(rt<<1|

1,mid+

1,r,x,y)

;return ans;

}}t1,t2;

ll ans[maxn]

;int

main()

q=read()

;for

(int i=

1;i<=q;i++

)que[i]

.l=read()

,que[i]

.r=read()

,que[i]

.id=i;

sort

(que+

1,que+

1+q,cmp)

;//詢問按右端點從小到大排序

for(

int i=

1;i<=n;i++

) r[n+1]

=n+1

; s.

insert(0

);s.

insert

(n+1);

//防止越界

for(

int i=

0;i<=n;i++

) alfa[i]

.push_back

(n+1);

//防止越界

int la=0;

for(

int j:alfa[i])}

sort

(b.begin()

,b.end()

,cmp2)

;int j=0;

for(

int i=

1;i<=q;i++

) ans[que[i]

.id]

=t1.

query(1

,1,n,que[i]

.l,que[i]

.r)*

(que[i]

.r+1

)-t2.

query(1

,1,n,que[i]

.l,que[i]

.r);

}for

(int i=

1;i<=q;i++

)printf

("%lld\n"

,ans[i]);

return0;

}

一道線段樹練習題

注意收到的傷害值寫的有點問題,實際上是a2 j 1 k ai j c j 2 sqrt k a c j 2 a2 j 1k ai,j cj 2 沒有後面的 a 首先由於題目中的限制 選了第i個敵人就再也不能和1到i 1的敵人作戰 我們可以觀察後得出dp ans i min ans u j 1k ai...

一道互動練習題

的做法 考慮逐位確定 對於每個位置,往後列舉有沒有位置可以使得正確位置更多,如果有,那麼有兩種情況,1是這個位置被放到了正確的位置,2是這個位置本來應該放的數被放來了 這裡的重點是我們需要區分1和2 具體的做法是記下讓這個位置答案正確位置數變大的2個位置,將其和i一起移位 這裡是手繪示意圖.即把p1...

一道fft練習題

考場上想到的o n 2 o n 2 o n2 暴力 記f i j f i j f i j 表示前i個位置,長度為j的連擊出現的期望次數 記g i j g i j g i j 表示第到i個位置為止,目前連擊次數為j的概率 轉移時有一些細節 include using namespace std con...