NOI2016 區間 解題報告

2022-04-29 20:30:13 字數 1366 閱讀 9231

最近思維好僵硬啊...

一上來就覺得先把區間拆成兩個端點進行差分,然後掃瞄位置序列,在每個位置維護答案,用資料結構維護當前位置的區間序列,但是不會維護。

於是想研究性質,想到為什麼要拿區間長度做權值呢,難道是有一些性質嗎

於是思考了很久區間長度的性質,猜了一些sb結論,比如什麼乙個區間只有加入時和刪除時的貢獻算一下就可以了之類的...

全錯了然後就自閉了...

然後想什麼欽定最大值,然後詢問位置區間,然後我發現線段樹每個點要掛乙個單調佇列(事實上把單調佇列從線段樹上拿下來就是正解了,我當時一點都沒想到),然後又自閉了

然後想乾脆欽定最大最小值,反正只有\(n^2\)種,然後我們需要查詢長度在最大最小值之間的區間,然後我們看一下這些區間的區間並有沒有乙個位置的值比\(m\)大,區間並可以染色,然後查詢最大值

這樣可以拿樹套樹暴力搞了,好像很對

然後發現如果掃瞄的最大值最小值兩個指標的話,移動是\(o(n)\)的,好像叫尺取法把,然後就可以只維護乙個線段樹了。

code:

#include #include #include using std::max;

const int size=1<<21;

char ibuf[size],*is,*it;

#define gc() (is==it?(it=(is=ibuf)+fread(ibuf,1,size,stdin),is==it?eof:*is++):*is++)

//#define gc() getchar()

template void read(t &x)

void ckmin(int &x,int y)

pushdown(id);

int mid=l+r>>1;

upt(ls,l,mid,l,r,d),upt(rs,mid+1,r,l,r,d);

mx[id]=max(mx[ls],mx[rs]);

}int qry(int id,int l,int r,int l,int r)

int main()

std::sort(saki+1,saki+1+m);

m=std::unique(saki+1,saki+1+m)-saki-1;

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

std::sort(toki+1,toki+1+n);

int l=1,r=1,ans=inf;

while(r<=n)

++r;

} if(ans==inf) puts("-1");

else printf("%d\n",ans);

return 0;

}

2019.5.30

題解 NOI2016區間

two pointer 第一題 大概就是對於一段連續的區間求解,使用兩個指標不斷卡區間的長度直到區間不滿足條件吧。這題只要對區間以長度從小到大排一下序,然後使用兩個指標指向區間。線段樹維護被覆蓋最多次數的節點被覆蓋了多少次。如果滿足條件,由於我們是在第一次判斷的時候發現它滿足條件的,所以最後加入的這...

NOI2016 區間 題解

題目大意 有n個區間,當有m個區間有公共部分時,求m個區間長度的最大值與最小值之差的最小值。思路 按區間的長度從小到大排序,可知連續的幾個區間最優,則用兩個指標指其頭尾,線性掃瞄,再用線段樹區間覆蓋。1 include2 include3 include4 define n 1000009 5 de...

線段樹 NOI2016 區間

在數軸上有 n 個閉區間 l 1,r1 l 2,r2 l n,rn 現在要從中選出 m 個區間,使得這 m個區間共同包含至少乙個位置。換句話說,就是使得存在乙個 x 使得對於每乙個被選中的區間 l i,ri 都有 li x r i 對於乙個合法的選取方案,它的花費為被選中的最長區間長度減去被選中的最...