【ybtoj】【线段树】魔法传输

题意

题解

花了比较长时间的一道题...
一开始有一个思路:开两个懒标记,分别记录区间左右端点加上的值,中间就可以根据等差数列维护
样例顺利通过,但是一交 (0pts) ,查了很久之后发现我更新左右端点增加的值的时候把线段树里 (l,r,x,y) 的意义弄混,导致 (lazy) 异常
简单改了改还是没改彻底,思路也许没错但是实在改不动了,贴下错误代码纪念一下自己的思路

错误代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls p<<1
#define rs p<<1|1
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
const int N = 1e5+10,mod = 1e9+7;
int n,m;
ll ans;
ll sum[N<<2],lazys[N<<2],lazye[N<<2];
inline void add(ll p,ll l,ll r,ll s,ll e)
{
    lazys[p]+=s,lazye[p]+=e;
    sum[p]+=(r-l+1)*(e+s)/2;
}
inline void pushdown(ll p,ll l,ll r)
{
	if(!lazys[p]&&!lazye[p]) return;
	ll mid=(l+r)>>1,x=(lazye[p]-lazys[p])/(r-l);
	add(ls,l,mid,lazys[p],lazys[p]+(mid-l)*x);
	add(rs,mid+1,r,lazys[p]+(mid+1-l)*x,lazye[p]);
//	printf("      (%lld,%lld)lazy:[%lld,%lld]
",l,r,lazys[p],lazye[p]);
	lazys[p]=lazye[p]=0;
}
void change(ll p,ll l,ll r,ll gl,ll gr,ll s,ll e)
{
	//printf(" change(%d)[%d,%d],(%d,%d) (%d,%d)
",p,l,r,gl,gr,s,e);
	if(gl<=l&&gr>=r) 
	{
		add(p,l,r,s,e);
		return;
	}
	ll x=1/*(e-s)/(r-l)*/;
	ll mid=(l+r)>>1;
	pushdown(p,l,r);
	if(gl<=mid) 
	{
		if(mid<=gr) change(ls,l,mid,gl,gr,s,s+(mid-gl)*x);
		else change(ls,l,mid,gl,gr,s,e);
		//change(ls,l,mid,gl,gr,s,s+(mid-l));
	}
	if(gr>=mid+1) 
	{
		if(gl<mid+1) change(rs,mid+1,r,gl,gr,s+(mid+1-gl)*x,e);
		else change(rs,mid+1,r,gl,gr,s,e);
		//change(ls,l,mid,gl,gr,s+(mid+1-l),e);
	}
	sum[p]=(sum[ls]+sum[rs])%mod; 
}
ll query(int p,int l,int r,int x)
{
	if(l==r) return sum[p]%mod;
	int mid=(l+r)>>1;
	pushdown(p,l,r); 
//	printf("   p=%d,(%d,%d):sum=%lld
",p,l,r,sum[p]);	
	ll ret=0;
	if(x<=mid) ret+=query(ls,l,mid,x);
	else ret+=query(rs,mid+1,r,x);
	return ret%mod;
}
int main()
{ 
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		ll l,r;
		//printf("    Case: %d
",i); 
		char op[3];
		scanf("%s",op);
		if(op[0]=='C') 
			l=read(),r=read(),change(1,1,n,l,r,1,r-l+1);
		else l=read(),printf("%lld
",query(1,1,n,l));
		//for(int i = 1 ; i <= n ; i ++)
		//	printf("%lld ",query(1,1,n,i));puts("");
	}
	return 0;
}
/*
300 13
C 240 286
C 68 89
C 172 273
Q 45
C 106 153
Q 122
Q 58
Q 83
Q 251
Q 17
Q 272
C 28 288
Q 232
*/

看了正解豁然开朗,差分直接转化成区间加了,查询前缀和即可,改了 (10min) 就 A 了...
只能说没有差分的意识
贴下正确代码

正确代码

#include<bits/stdc++.h>
using namespace std;
#define ll long long
#define ls p<<1
#define rs p<<1|1
inline ll read()
{
	ll ret=0;char ch=' ',c=getchar();
	while(!(c>='0'&&c<='9')) ch=c,c=getchar();
	while(c>='0'&&c<='9') ret=(ret<<1)+(ret<<3)+c-'0',c=getchar();
	return ch=='-'?-ret:ret;
}
const int N = 1e5+10,mod = 1e9+7;
int n,m;
ll ans;
ll sum[N<<2],lazy[N<<2];
inline void add(ll p,ll l,ll r,ll v)
{
	sum[p]+=(r-l+1)*v;
	lazy[p]+=v;
}
inline void pushdown(ll p,ll l,ll r)
{
	if(!lazy[p]) return;
	ll mid=(l+r)>>1;
	add(ls,l,mid,lazy[p]);
	add(rs,mid+1,r,lazy[p]);
	lazy[p]=0;
}
void change(ll p,ll l,ll r,ll gl,ll gr,ll v)
{
	//printf(" change(%d)[%d,%d],(%d,%d) (%d,%d)
",p,l,r,gl,gr,s,e);
	if(gl<=l&&gr>=r) 
	{
		add(p,l,r,v);
		return;
	}
	ll mid=(l+r)>>1;
	pushdown(p,l,r);
	if(gl<=mid) change(ls,l,mid,gl,gr,v);
	if(gr>=mid+1) change(rs,mid+1,r,gl,gr,v);
	sum[p]=(sum[ls]+sum[rs])%mod; 
}
ll query(int p,int l,int r,int x,int y)
{
	if(x<=l&&r<=y) return sum[p]%mod;
	int mid=(l+r)>>1;
	pushdown(p,l,r); 
	ll ret=0;
	if(x<=mid) (ret+=query(ls,l,mid,x,y))%=mod;
	if(y>mid)  (ret+=query(rs,mid+1,r,x,y))%=mod;
	return ret;
}
int main()
{ 
	n=read(),m=read();
	for(int i=1;i<=m;i++)
	{
		ll l,r; 
		char op[3];
		scanf("%s",op);
		if(op[0]=='C') 
			l=read(),r=read(),change(1,1,n,l,r,1),change(1,1,n,r+1,r+1,-(r-l+1));
		else l=read(),printf("%lld
",query(1,1,n,1,l));
	}
	return 0;
}
/*
300 13
C 240 286
C 68 89
C 172 273
Q 45
C 106 153
Q 122
Q 58
Q 83
Q 251
Q 17
Q 272
C 28 288
Q 232
*/
原文地址:https://www.cnblogs.com/conprour/p/15292319.html