線段樹學習筆記 1
阿新 • • 發佈:2021-11-13
\[\huge\color{cornflowerblue}{\texttt{Segment Tree studying notes: NO.1.}}
\]\[\large\color{gold}{\texttt{Only Problems Here.}}
\]
\[\color{skyblue}{\texttt{And We,}} \]\[\color{skyblue}{\texttt{We Burn Faster Than Lights,}} \]\[\color{skyblue}{\texttt{Shine Across In The Night Sky,}} \]\[\color{skyblue}{\texttt{We Burn Faster Than Lights.}} \]\[\color{gold}{◢_◤} \]
\(\tt{P1712}\) 區間
\[\huge\color{silver}{\texttt{1.鋰性分析}} \]做不出來,爬了爬了
看到題
: 喲,標籤全都認識,跟網路流的某些水題估計一個水平
1h later
: 好我覺得這是正解
然後用1h
打了一個既不離散化也不正解的線段樹(((
考慮把所有區間按長度排序之後離散化,這樣方便尺取統計答案.
尺取程式碼:
int l=1,r=1; while(r<=n) { modify(1,nd[r].left,nd[r].right,1); while(tr[1].v>=m) { ans=min(ans,nd[r].len-nd[l].len); modify(1,nd[l].left,nd[l].right,-1); l++; } r++; }
- \(\tt{Cytti\;\;\;\;\boxed{AKer}:為什麼不用考慮尺取的時候不連續地取區間更優?}\)
因為區間序列排序後有單調性,答案統計的是有效的區間
,即使在答案所選最少區間之外將所有長度介於maxn
和minn
的區間全部選取也不影響答案,所以可以直接尺取.
#include <bits/stdc++.h> //WA very fucking bad() #define ri register int #define MAXN 500005 #define int long long using namespace std; const int inf=0x3f3f3f3f; int n,m; int ans=inf; int cnt; int nd2[MAXN<<1]; struct node{ int left,right,len; }nd[MAXN]; inline bool cmp(node a,node b) { return a.len<b.len; } inline int r() { int fed=0; char in=getchar(); bool flag=1; while(!isdigit(in)) flag&=(in!='-'),in=getchar(); while(isdigit(in)) fed=fed*10+in-'0',in=getchar(); return (2*flag-1)*fed; } struct seg_tree{ int l,r; int tag; int v; }tr[MAXN<<3]; inline void push_up(int u) { // if(tr[u<<1].pos+tr[u<<1].len>=tr[u<<1|1].pos) // { // tr[u].minn=min(tr[u<<1].minn,tr[u<<1|1].minn); // tr[u].maxn=max(tr[u<<1].maxn,tr[u<<1|1].maxn); // tr[u].pos=tr[u<<1|1].pos; // tr[u].len=tr[u<<1].pos+tr[u<<1].len-tr[u<<1|1].pos; // tr[u].tot=tr[u<<1].tot+tr[u<<1|1].tot; // //printf("NODE:%d>>> minn=%d maxn=%d pos=%d len=%d tot=%d\n",u,tr[u].minn,tr[u].maxn,tr[u].pos,tr[u].len,tr[u].tot); // } //以上為女子亻弋石馬 tr[u].v=max(tr[u<<1].v,tr[u<<1|1].v); } inline void push_down(int u) { tr[u<<1].tag+=tr[u].tag; tr[u<<1|1].tag+=tr[u].tag; tr[u<<1].v+=tr[u].tag; tr[u<<1|1].v+=tr[u].tag; tr[u].tag=0; } inline void build(int u,int l,int r) { tr[u].l=l,tr[u].r=r; if(l==r) return; int mid=l+r>>1; build(u<<1,l,mid); build(u<<1|1,mid+1,r); } inline void modify(int u,int l,int r,int d) { if(tr[u].l>=l&&tr[u].r<=r) { tr[u].tag+=d; tr[u].v+=d; return; } if(tr[u].tag) push_down(u); int mid=tr[u].l+tr[u].r>>1; if(l<=mid) modify(u<<1,l,r,d); if(r>mid) modify(u<<1|1,l,r,d); push_up(u); } signed main() { n=r(),m=r(); for(ri i=1;i<=n;i++) { nd[i].left=r(); nd[i].right=r(); nd[i].len=nd[i].right-nd[i].left; nd2[++cnt]=nd[i].left; nd2[++cnt]=nd[i].right; } sort(nd+1,nd+n+1,cmp); sort(nd2+1,nd2+cnt+1); int len=unique(nd2+1,nd2+cnt+1)-nd2-1; for(ri i=1;i<=n;i++) { nd[i].left=lower_bound(nd2+1,nd2+len+1,nd[i].left)-nd2; nd[i].right=lower_bound(nd2+1,nd2+len+1,nd[i].right)-nd2; } build(1,1,len); int l=1,r=1; while(r<=n) { modify(1,nd[r].left,nd[r].right,1); while(tr[1].v>=m) { ans=min(ans,nd[r].len-nd[l].len); modify(1,nd[l].left,nd[l].right,-1); l++; } r++; } if(ans!=inf) printf("%lld",ans); else puts("-1"); return 0; }
\[\color{skyblue}{\texttt{And We,}} \]\[\color{skyblue}{\texttt{We Burn Faster Than Lights,}} \]\[\color{skyblue}{\texttt{Shine Across In The Night Sky,}} \]\[\color{skyblue}{\texttt{We Burn Faster Than Lights.}} \]\[\color{gold}{◢_◤} \]