乙個簡單的區間問題

2021-09-05 04:03:12 字數 3837 閱讀 7284

徐寅展**裡的題

為了敘述方便,不妨稱題目中初始給出的賦值操作為第一類操作,賦值操作因為會直接覆蓋前面操作的貢獻,所以有一定的時間作用區間,那麼按時間作用區間處理後得到新的操作,不妨稱之為第二類操作。

考慮用線段樹先模擬一遍,乙個標記會把原來在它子樹中的操作無效化,記得下推標記時要把標記**。但是這樣的運算元就達到了o(m

log⁡n)

o(m\log n)

o(mlogn)

。但如果仔細分析,以操作塊數作為勢能函式,那麼每個操作頂多增加2的勢能,所以總的勢能其實是o(m

)o(m)

o(m)

的。因此要把子樹中相同的操作合併起來。收集標記可以暴力dfs,勢能分析可證複雜度上限為o(m

log⁡2n

)o(m\log^2 n)

o(mlog2n

)。經過處理後的第二類操作,如果在時間線段樹上有交集,則他們必定在空間上無交集。把第二類操作打到時間線段樹上去。那麼怎麼處理詢問呢,整體二分??然後複雜度又變成o(m

log⁡3n

)o(m\log^3 n)

o(mlog3n

)的了有乙個巧妙的處理方法,詢問是乙個葉子上的,它的答案都是到根的路徑上的操作做的貢獻,那麼我們就摒棄以前字首和的方法,單獨考慮每個節點。考慮把詢問加入到葉子到根上所有點中去,如果我們把每個節點中的操作按照權值排序,那麼就只需要用乙個資料結構支援區間加和區間求和了!所有的修改和詢問總的複雜度為o(m

log⁡2n

)o(m\log^2 n)

o(mlog2n

)。綜上,時間複雜度為o(m

log⁡2n

)o(m\log^2 n)

o(mlog2n

)。好久沒打過行數100+的**了,又有了之前做資料結構碼農題時的那種欲生欲死的感覺…

#include

#include

#include

#define lowbit(x) ((x)&(-(x)))

using

namespace std;

typedef

long

long ll;

const

int maxn=

100010

;template

<

typename tp>

inline

intgetmin

(tp &x,tp y)

template

<

typename tp>

inline

intgetmax

(tp &x,tp y)

template

<

typename tp>

inline

void

read

(tp &x)

int n,m,tm,oc,qc,stk[maxn]

,ans[maxn]

;struct oper

oper operator+(

const oper &t)

const

}q[maxn<<1]

,qy[maxn]

;struct bit

ll query

(int p)

}bit;

struct time_sgt

int m=

(l+r)

>>1;

if(l<=m)

update

(l,m,l,r,rt<<

1,t);if

(mupdate

(m+1

,r,l,r,rt<<1|

1,t);}

void

addq

(int l,

int r,

int pos,

int rt,oper t)

void

dfs(

int l,

int r,

int rt)

for(itr=op[rt]

.begin()

;itr!=op[rt]

.end()

;++itr)if(

!itr-

>op)

bit.

add(itr-

>l,-1

),bit.

add(itr-

>r+1,

1);if

(l==r)

return

;int m=

(l+r)

>>1;

dfs(l,m,rt<<1)

;dfs

(m+1

,r,rt<<1|

1);}

}t;struct sgt

;getmin

(tmp[rt<<1]

.r,m)

;getmax

(tmp[rt<<1|

1].l,m+1)

;}void

build

(int l,

int r,

int rt)

int m=

(l+r)

>>1;

build

(l,m,rt<<1)

;build

(m+1

,r,rt<<1|

1);}

void

dfs(

int l,

int r,

int rt);}

if(l==r)

int m=

(l+r)

>>

1;sz[rt]=0

;dfs

(l,m,rt<<1)

;dfs

(m+1

,r,rt<<1|

1);}

void

update

(int l,

int r,

int l,

int r,

int rt,oper t)

int m=

(l+r)

>>1;

if(tag[rt]

)pushdown

(l,m,r,rt);if

(l<=m)

update

(l,m,l,r,rt<<

1,t);if

(mupdate

(m+1

,r,l,r,rt<<1|

1,t)

; sz[rt]

=sz[rt<<1]

|sz[rt<<1|

1]|tag[rt];}

}sgt;

void

input()

sgt.

build(1

,n,1);

for(

int i=

1;i<=m;i++

);now=sgt.xu[1]

;for

(int j=

2;j<=sgt.cnt;j++)}

if(op==2)

} sgt.cnt=

0;sgt.

dfs(

1,n,1)

;sgt.xu[

++sgt.cnt]

=(oper)

;now=sgt.xu[1]

;for

(int j=

2;j<=sgt.cnt;j++

)for

(int i=

1;i<=qc;i++

) t.

addq(1

,n+m,qy[i]

.tm,

1,qy[i]);

}int

main()

問題 A 乙個簡單的整數問題

問題 a 乙個簡單的整數問題 時間限制 5 sec 記憶體限制 128 mb 提交 75 解決 25 提交 狀態 討論版 命題人 quanxing edit testdata 題目描述 你有 n個整數,a1,a2,an。你需要處理兩種操作。一種操作是在給定間隔中為每個數字新增一些給定數字。另一種是要...

FAFU OJ 乙個簡單的問題

乙個簡單的問題 time limit 1000ms memory limit 65536kb total submissions 1386 accepted 240 share description 給定n個正整數和乙個正整數p,要求你從中找出兩個數字a,b使得a b p input 第一行兩個數...

乙個簡單的怪問題

乙個學員問了乙個關於io的怪問題,問題是這樣的 讀取鍵盤輸入的乙個字元,然後列印輸出這個字元,在列印字元的前面和後面分別加了乙個字串,程式的 如下 public class test 編譯並執行這個程式。1 輸入字元 a 命令列視窗列印輸出的結果如圖1所示,與我們預期的一樣。2 重新執行這個程式,直...