1. 程式人生 > 其它 >線段樹學習筆記 1

線段樹學習筆記 1

\[\huge\color{cornflowerblue}{\texttt{Segment Tree studying notes: NO.1.}} \]\[\large\color{gold}{\texttt{Only Problems Here.}} \]

\(\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}:為什麼不用考慮尺取的時候不連續地取區間更優?}\)

因為區間序列排序後有單調性,答案統計的是有效的區間,即使在答案所選最少區間之外將所有長度介於maxnminn的區間全部選取也不影響答案,所以可以直接尺取.

\[\huge\color{silver}{\texttt{2.感性開打}} \]
#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}{◢_◤} \]