首页 > 代码库 > ●线段树题之wows

●线段树题之wows

●模拟考试的一道似乎是学长出的题,还不错,挺考代码能力的。以此记录。

技术分享

(像手纸一样长的贴图……)

●题目大意:

   有横向排布的n个点,每个点初始值都为0。

   有m个操作(先输入操作类型com):

     com==0:修改操作(接着输入l , r , a , k , p),解释见输入格式。(提供图帮助理解)。

    技术分享

     com==1:查询操作(接着输入l , r),输出区间[ l , r ]内最长的等差数列的项数(要连续)。

●题解:

     注意到是要找等差数列,即答案对应的区间个元素的差值应相等。即可以前后两元素的差值建线段树,然后维护区间最长的差值相等的一段。

     (是不是思路很清晰,然而恶心的代码却搞了我大半个上午。)

●附上代码:

我上代码咯:(附上测试数据)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
struct segment{
	int l,r,nl,nr,mx,ml,mr,lazy;
}t[400005]; 
int n,m;
void pushdown(int u)
{
	t[u*2].lazy+=t[u].lazy; t[u*2].nl+=t[u].lazy; t[u*2].nr+=t[u].lazy;
	t[u*2+1].lazy+=t[u].lazy; t[u*2+1].nl+=t[u].lazy; t[u*2+1].nr+=t[u].lazy;
	t[u].lazy=0;
}
void pushup(int u)
{
	t[u].mx=max(t[u*2].mx,t[u*2+1].mx);
	t[u].ml=t[u*2].ml;
	t[u].mr=t[u*2+1].mr;
	t[u].nl=t[u*2].nl;                  
	t[u].nr=t[u*2+1].nr;                
	if(t[u*2].nr==t[u*2+1].nl)
	{
		t[u].mx=max(t[u].mx,t[u*2].mr+t[u*2+1].ml);
		if(t[u*2].ml==(t[u*2].r-t[u*2].l+1)) t[u].ml+=t[u*2+1].ml;
		if(t[u*2+1].mr==(t[u*2+1].r-t[u*2+1].l+1)) t[u].mr+=t[u*2].mr;
	}
}
void build(int u,int l,int r)
{
	t[u]=(segment){l,r,0,0,r-l+1,r-l+1,r-l+1};
	if(l==r) return;
	int mid=(l+r)/2;
	build(u*2,l,mid);
	build(u*2+1,mid+1,r);
}
void add(int u,int l,int r,int x)
{
	if(l<=t[u].l&&t[u].r<=r)
	{
		t[u].nl+=x;
		t[u].nr+=x;
		t[u].lazy+=x;
		return;
	}
	if(t[u].lazy) pushdown(u);
	int mid=(t[u].l+t[u].r)/2;
	if(l<=mid) add(u*2,l,r,x);
	if(mid<r) add(u*2+1,l,r,x);
	pushup(u); 
}
void query(int u,int l,int r,int &mx,int &lm,int &rm,int &ln,int &rn)
{
	int lmx=0,lml,lmr,lnl,lnr,rmx=0,rml,rmr,rnl,rnr;
	if(t[u].l==l&&t[u].r==r)
	{
		mx=t[u].mx; lm=t[u].ml; rm=t[u].mr; ln=t[u].nl; rn=t[u].nr;
		return;
	}
	if(t[u].lazy) pushdown(u);
	int mid=(t[u].l+t[u].r)/2;
	if(l<=mid) query(u*2,l,min(mid,r),lmx,lml,lmr,lnl,lnr);
	if(mid<r) query(u*2+1,max(mid+1,l),r,rmx,rml,rmr,rnl,rnr);
	if(lmx*rmx!=0)
	{
		mx=max(lmx,rmx);
		ln=lnl; rn=rnr; lm=lml; rm=rmr;
		if(lnr==rnl) 
		{
			mx=max(mx,lmr+rml);
			if(lml==mid-l+1) lm+=rml;
			if(rmr==r-(mid+1)+1) rm+=lmr;
		}
	}
	else
	{
		if(lmx==0) swap(lmx,rmx),swap(lml,rml),swap(lmr,rmr),swap(lnl,rnl),swap(lnr,rnr);
		mx=lmx; lm=lml; rm=lmr; ln=lnl; rn=lnr;
	}
}
int main()
{
	freopen("wows.in","r",stdin);
	freopen("wows.out","w",stdout);
	scanf("%d%d",&n,&m);n--;
	build(1,1,n); int com;
	for(int i=1,l,r,a,k,p;i<=m;i++)
	{
		scanf("%d",&com);
		if(com==0) 
		{
			scanf("%d%d%d%d%d",&l,&r,&a,&k,&p);
			if(l>1) add(1,l-1,l-1,a);
			if(p-1>=l) add(1,l,p-1,k);
			if(r-1>=p) add(1,p,r-1,-k);
			if(r<n) add(1,r,r,-(a+(2*p-l-r)*k));
		}
		if(com==1)
		{
			int ans,a1,a2,a3,a4;
			scanf("%d%d",&l,&r); r--;
			query(1,l,r,ans,a1,a2,a3,a4);
			printf("%d\n",ans+1);
		}
	}
	return 0;
}

●线段树题之wows