• 序列[势能线段树]


    也许更好的阅读体验

    (mathcal{Description})
    两个长度为(n)的序列,(a),(b),其中(a)最开始是一个全(0)序列,(b)是一个排列
    你要用数据结构维护这样的两个操作

    • (a)([l,r])内所有的数加(1)
    • 询问(sumlimits_{i=l}^r lfloorfrac{a_i}{b_i} floor)

    (n)和询问数均不超过(10^5)

    (mathcal{Solution})

    机房某大佬告诉咱这是势能线段树?
    对于每个(i),每被加(b_i)次就产生(1)的贡献,考虑维护这个过程
    用一颗线段树,维护每个点的最大值和最大值在那个子树
    每个节点的初值设为(-b_i)
    支持一下区间加,当发现当前最大值为(0)时,就将那个点找到并加(1)的贡献,贡献可用同一颗线段树或者树状数组维护
    然后将那个点(()设为(i))重新赋值为(-b_i)
    最多产生(nlogn)次贡献,每次维护(logn)
    总复杂度(nlog^2n)

    (mathcal{Code})

    /*******************************
    Author:Morning_Glory
    LANG:C++
    Created Time:2019年10月21日 星期一 18时59分47秒
    *******************************/
    #include <cstdio>
    #include <fstream>
    #include <algorithm>
    using namespace std;
    const int maxn = 100005;
    const int maxt = 1000006;
    //{{{cin
    struct IO{
    	template<typename T>
    	IO & operator>>(T&res){
    		res=0;
    		bool flag=false;
    		char ch;
    		while((ch=getchar())>'9'||ch<'0')	flag|=ch=='-';
    		while(ch>='0'&&ch<='9')	res=(res<<1)+(res<<3)+(ch^'0'),ch=getchar();
    		if (flag)	res=~res+1;
    		return *this;
    	}
    }cin;
    //}}}
    int n,m;
    int h[maxn];
    namespace SegmentTree{
    	//其实可以不包装
    	int lt[maxt],rt[maxt],ans[maxt],val[maxt],loc[maxt],lazy[maxt];
    	#define cl (k<<1)
    	#define cr (k<<1|1)
    	#define lm (lt[k]+rt[k])/2
    	#define rm (lt[k]+rt[k])/2+1
    	//{{{pushup
    	void pushup (int k)
    	{
    		if (lt[k]==rt[k])	return;
    		if (val[cl]>val[cr])	val[k]=val[loc[k]=cl];
    		else	val[k]=val[loc[k]=cr];
    		ans[k]=ans[cl]+ans[cr];
    	}
    	//}}}
    	//{{{build
    	void build (int l,int r,int k=1)
    	{
    		lt[k]=l,rt[k]=r;
    		if (l==r)	return loc[k]=k,val[k]=-h[l],void();
    		build(l,lm,cl),build(rm,r,cr);
    		pushup(k);
    	}
    	//}}}
    	//{{{pushdown
    	void pushdown (int k)
    	{
    		val[cl]+=lazy[k],val[cr]+=lazy[k];
    		lazy[cl]+=lazy[k],lazy[cr]+=lazy[k];
    		lazy[k]=0;
    	}
    	//}}}
    	//{{{update
    	void update (int k)
    	{
    		if (lt[k]==rt[k])	return ++ans[k],val[k]=-h[lt[k]],void();
    		if (lazy[k])	pushdown(k);
    		update(loc[k]);
    		pushup(k);
    	}
    	//}}}
    	//{{{modify
    	void modify (int l,int r,int k=1)
    	{
    		if (lt[k]>=l&&rt[k]<=r){
    			++val[k],++lazy[k];
    			while (!val[k])	update(k);
    			return ;
    		}
    		if (lazy[k])	pushdown(k);
    		if (l<=lm)	modify(l,r,cl);
    		if (r>=rm)	modify(l,r,cr);
    		pushup(k);
    	}
    	//}}}
    	//{{{query
    	int query (int l,int r,int k=1)
    	{
    		if (lt[k]>=l&&rt[k]<=r)	return ans[k];
    		if (lazy[k])	pushdown(k);
    		int res=0;
    		if (l<=lm)	res+=query(l,r,cl);
    		if (r>=rm)	res+=query(l,r,cr);
    		return res;
    	}
    	//}}}
    }
    using namespace SegmentTree;
    int main()
    {
    	cin>>n>>m;
    	for (int i=1;i<=n;++i)	cin>>h[i];
    	build(1,n);
    	for (int i=1;i<=m;++i){
    		int opt,l,r;
    		cin>>opt>>l>>r;
    		if (opt==1)	modify(l,r);
    		else	printf("%d
    ",query(l,r));
    	}
    	return 0;
    }
    
    

    如有哪里讲得不是很明白或是有错误,欢迎指正
    如您喜欢的话不妨点个赞收藏一下吧

  • 相关阅读:
    激活函数(ReLU, Swish, Maxout)
    损失函数
    md5sum命令行使用注意事项
    Jetson ARM SeetaFace编译
    Linux下的wine生活(QQ/微信/Office)
    人脸识别引擎SeetaFace编译 ubuntu
    Python为8bit深度图像应用color map
    MySQL、MongoDB、Redis数据库Docker镜像制作
    bash的管道符与重定向
    Docker 及 nvidia-docker 使用
  • 原文地址:https://www.cnblogs.com/Morning-Glory/p/11715639.html
Copyright © 2020-2023  润新知