线段树学习笔记 1


\[\huge\color{cornflowerblue}{\texttt{Segment Tree studying notes: NO.1.}} \]

\[\large\color{gold}{\texttt{Only Problems Here.}} \]


  • OI-WIKI上の线段树

\(\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 
//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=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}{◢_◤} \]