• 【LOJ#6029】市场(线段树)


    【LOJ#6029】市场(线段树)

    题面

    LOJ

    题解

    看着就是一个需要势能分析的线段树。
    不难发现就是把第二个整除操作化为减法。
    考虑一下什么时候整除操作才能变成减法。
    假设两个数为(a,b)。那么就有(displaystyle a-[frac{a}{d}]=b-[frac{b}{d}])
    那么假设(a,b)整除的结果分别为(aa,bb)(a=d*aa+p_a,b=d*bb+p_b)
    得到:(displaystyle (d-1)aa+p_a=(d-1)bb+p_b)
    化简后得到:(displaystyle (d-1)(aa-bb)=p_b-p_a)
    显然(p_a,p_b)的取值范围就是([0,d)),而左边还乘了一个(d-1)。也就意味着这个限制是非常强的,假设(aa>bb)(等于就必定相等了,没什么好考虑的),那么(p_b-p_bin[0,d))。左边显然只能取(1),右边显然只能去(d-1)。写出来就是:(a=d*aa,b=d*(aa-1)+d-1)。所以我们得到(a-b=1)
    因此维护区间最大值和最小值,如果最大值和最小值整除操作之后的差相等,那么可以变为区间减法。否则暴力下放。
    至于复杂度?听(zsy)口胡了一下他的分析。单独考虑一个线段树节点,它最多被暴力访问(loga)次。如果区间加法则重置这个(log)。而每次区间加法最多影响(logn)个区间,也就是会重置(logn)个区间的访问次数。而(m)次操作最多重置(mlogn)个区间,因此最多增加访问次数是(loga)次。所以总的复杂度就是(O((n+mlogn)loga))
    感觉很对的样子。
    注意一下负数的向下取整。

    #include<iostream>
    #include<cstdio>
    using namespace std;
    #define ll long long
    #define MAX 100100
    #define lson (now<<1)
    #define rson (now<<1|1)
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    struct Node{ll v;int mn,mx,tag;}t[MAX<<2];
    void pushup(int now)
    {
    	t[now].mn=min(t[lson].mn,t[rson].mn);
    	t[now].mx=max(t[lson].mx,t[rson].mx);
    	t[now].v=t[lson].v+t[rson].v;
    }
    void Build(int now,int l,int r)
    {
    	if(l==r){t[now].v=t[now].mn=t[now].mx=read();return;}
    	int mid=(l+r)>>1;
    	Build(lson,l,mid);Build(rson,mid+1,r);
    	pushup(now);
    }
    void puttag(int now,int l,int r,int w)
    {
    	t[now].v+=(r-l+1)*w;
    	t[now].tag+=w;t[now].mn+=w;t[now].mx+=w;
    }
    void pushdown(int now,int l,int r)
    {
    	if(!t[now].tag)return;
    	int mid=(l+r)>>1;
    	puttag(lson,l,mid,t[now].tag);
    	puttag(rson,mid+1,r,t[now].tag);
    	t[now].tag=0;
    }
    void Modify(int now,int l,int r,int L,int R,int w)
    {
    	if(L<=l&&r<=R){puttag(now,l,r,w);return;}
    	int mid=(l+r)>>1;pushdown(now,l,r);
    	if(L<=mid)Modify(lson,l,mid,L,R,w);
    	if(R>mid)Modify(rson,mid+1,r,L,R,w);
    	pushup(now);
    }
    int Div(int a,int d)
    {
    	if(a>=0)return a/d-a;
    	if(a%d==0)return a/d-a;
    	return a/d-1-a;
    }
    void ModifyDiv(int now,int l,int r,int L,int R,int d)
    {
    	if(L<=l&&r<=R)
    		if(Div(t[now].mx,d)==Div(t[now].mn,d))
    		{puttag(now,l,r,Div(t[now].mx,d));return;}
    	int mid=(l+r)>>1;pushdown(now,l,r);
    	if(L<=mid)ModifyDiv(lson,l,mid,L,R,d);
    	if(R>mid)ModifyDiv(rson,mid+1,r,L,R,d);
    	pushup(now);
    }
    ll Query(int now,int l,int r,int L,int R)
    {
    	if(L<=l&&r<=R)return t[now].v;
    	int mid=(l+r)>>1;pushdown(now,l,r);
    	ll ret=0;
    	if(L<=mid)ret+=Query(lson,l,mid,L,R);
    	if(R>mid)ret+=Query(rson,mid+1,r,L,R);
    	return ret;
    }
    int Querymn(int now,int l,int r,int L,int R)
    {
    	if(L==l&&r==R)return t[now].mn;
    	int mid=(l+r)>>1;pushdown(now,l,r);
    	if(R<=mid)return Querymn(lson,l,mid,L,R);
    	if(L>mid)return Querymn(rson,mid+1,r,L,R);
    	return min(Querymn(lson,l,mid,L,mid),Querymn(rson,mid+1,r,mid+1,R));
    }
    int n,Q;
    int main()
    {
    	n=read();Q=read();
    	Build(1,1,n);
    	while(Q--)
    	{
    		int opt=read(),l=read()+1,r=read()+1;
    		if(opt==1)Modify(1,1,n,l,r,read());
    		if(opt==2)ModifyDiv(1,1,n,l,r,read());
    		if(opt==3)printf("%d
    ",Querymn(1,1,n,l,r));
    		if(opt==4)printf("%lld
    ",Query(1,1,n,l,r));
    	}
    	return 0;
    }
    
  • 相关阅读:
    python lambda函数的用法
    python 中is 和 ==的区别
    Mongo 聚合函数 $group方法的使用
    mongo聚合
    当mongo数据库报错关于 Failed global initialization:
    python 中字符串的拼接
    python eval()用法报错 SyntaxError: unexpected EOF while parsing
    高性能MySQL(六):选择合适的存储引擎
    高性能MySQL(五):存储引擎
    高性能MySQL(四):多版本并发控制
  • 原文地址:https://www.cnblogs.com/cjyyb/p/10187891.html
Copyright © 2020-2023  润新知