• Luogu P1438无聊的序列【线段树/差分】By cellur925


    题目传送门

    题目大意:维护一个序列,维护区间加等差数列,单点查询的操作。

    首先我们肯定是要用线段树来维护了,按照一般的思维局限,我选择了维护序列中的值,但是区间修改的时候由于公差的存在,所以区间修改有些难搞。后来又想分别维护(k)(d),但是最终失败了。

    正解十分巧妙,维护的是一个差分序列。如何维护?我们把(l)位置加上(k),把([l,r))的位置加上(d),再把(r+1)的位置减去(k+d*(r-l))。当查询的时候我们只要做一遍前缀和就好了。

    然后??上一个线段树的区间修改+查询的板子就好了==。

    #include<cstdio>
    #include<algorithm>
    #define maxn 100090
    
    using namespace std;
    typedef long long ll;
    
    int n,m;
    ll k,d,seq[maxn];
    struct SegmentTree{
    	int l,r;
    	ll val,lazy;
    }t[maxn*4];
    
    void build(int p,int l,int r)
    {
    	t[p].l=l,t[p].r=r;
    	if(l==r) return ;
    	int mid=(l+r)>>1;
    	build(p<<1,l,mid);
    	build(p<<1|1,mid+1,r);
    }
    
    void update(int p)
    {
    	if(!t[p].lazy||t[p].l==t[p].r) return ;
    	t[p<<1].lazy+=t[p].lazy;
    	t[p<<1|1].lazy+=t[p].lazy;
    	t[p<<1].val+=t[p].lazy*(t[p<<1].r-t[p<<1].l+1);
    	t[p<<1|1].val+=t[p].lazy*(t[p<<1|1].r-t[p<<1|1].l+1);
    	t[p].lazy=0;
    }
    
    void change(int p,int l,int r,ll x)
    {
    	update(p);
    	if(t[p].l==l&&t[p].r==r)
    	{
    		t[p].val+=1ll*x*(r-l+1);
    		t[p].lazy+=x;
    		return ;
    	}
    	int mid=(t[p].l+t[p].r)>>1;
    	if(l>mid) change(p<<1|1,l,r,x);
    	else if(r<=mid) change(p<<1,l,r,x);
    	else change(p<<1,l,mid,x),change(p<<1|1,mid+1,r,x);
    	t[p].val=t[p<<1].val+t[p<<1|1].val;
    }
    
    ll ask(int p,int l,int r)
    {
    	update(p);
    	if(t[p].l==l&&t[p].r==r) return t[p].val;
    	int mid=(t[p].l+t[p].r)>>1;
    	if(l>mid) return ask(p<<1|1,l,r);
    	else if(r<=mid) return ask(p<<1,l,r);
    	else return ask(p<<1,l,mid)+ask(p<<1|1,mid+1,r);
    }
    
    int main()
    {
    	scanf("%d%d",&n,&m);
    	for(int i=1;i<=n;i++) scanf("%lld",&seq[i]);
    	build(1,1,n);
    	for(int i=1;i<=m;i++)
    	{
    		int op=0,p=0;
    		scanf("%d",&op);
    		if(op==1)
    		{
    			int l=0,r=0;
    			scanf("%d%d%lld%lld",&l,&r,&k,&d);
    			change(1,l,l,k);
    			if(r>l) change(1,l+1,r,d);
    			if(r!=n) change(1,r+1,r+1,-k-d*(r-l));
    		}
    		else if(op==2) scanf("%d",&p),printf("%lld
    ",seq[p]+ask(1,1,p));
    	}
    	return 0;
    }
    

    注意:防止RE,修改的时候在([l+1,r))区间改的时候要注意是不是(l=r);以及在(r+1)修改的时候判断是不是右区间为(n)

    还是思维不要被僵化啊。

  • 相关阅读:
    简单介绍三层架构
    Java字符串常量池是什么?为什么要有这种常量池?
    java中String、StringBuffer和StringBuilder的区别(简单介绍)
    java中equals以及==的用法(简单介绍)
    关于java中Exception异常
    职场沟通,别光靠嘴
    小目标 | DAX高级实践-Power BI与Excel联合应用
    本号讯 | 微软和百度携手推进全球自动驾驶技术; 微软发布新一代可垂直可水平滚动的Arc鼠标
    你有一枚私人同声传译员待领取
    有了这套物联网节水平台,他决定回去继续管理农场
  • 原文地址:https://www.cnblogs.com/nopartyfoucaodong/p/9902076.html
Copyright © 2020-2023  润新知