zoukankan      html  css  js  c++  java
  • 【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
    */
    
  • 相关阅读:
    一些比较实用的小函数
    开发KOL程序 (1)
    开发KOL程序2
    使用mask来制作图像透明
    用U盘方便快捷安装系统
    Windows记忆专家
    Delphi开发桌面图标列表查看程序
    js压缩上传图片,转载
    js操作二进制数据
    mui扫码横屏全屏
  • 原文地址:https://www.cnblogs.com/conprour/p/15292319.html
Copyright © 2011-2022 走看看