线段树动态开点

其实在tzt版线段树的基础上稍微加一些东西就好了。我们不预先开点,每当需要用到一个点时,我们才开。空间复杂度可以优化到 m(查询)log n。

code(线段树1,其实这道题用动态开点没啥意义没啥意义,当作练习)

#include<iostream>
#include<cstdio>
#include<queue>
#include<algorithm>
#include<cstring>
#include <stack>
#include<vector>
#define half (l+r)>>1;
using namespace std;
int n,m;
const int maxn=400000;
struct hzw
{
	int sum;
	int add;
	int lc;
	int rc;  
}t[maxn];
int a[maxn],tot;
inline void update(int &s,int l,int r,int cl,int cr,int x)
{
	if (!s) s=++tot;
    t[s].sum+=(cr-cl+1)*x;
    if (l==cl&&r==cr)
    {
    	t[s].add+=x;
    	return ;
    }
    int mid=half;
    if (cr<=mid)     update(t[s].lc,l,mid,cl,cr,x);
	else if (cl>mid) update(t[s].rc,mid+1,r,cl,cr,x);
	else {
		update(t[s].lc,l,mid,cl,mid,x);
		update(t[s].rc,mid+1,r,mid+1,cr,x);
	}
}
inline int query(int s,int l,int r,int cl,int cr,int cnt)
{
	if (!s) return 0;
	if (l==cl&&r==cr)
	{
		return cnt*(cr-cl+1)+t[s].sum;
	}
	int mid=half;
	if (cr<=mid)     return query(t[s].lc,l,mid,cl,cr,cnt+t[s].add);
	else if (cl>mid) return query(t[s].rc,mid+1,r,cl,cr,cnt+t[s].add);
	else {
		return query(t[s].lc,l,mid,cl,mid,t[s].add+cnt)+query(t[s].rc,mid+1,r,mid+1,cr,cnt+t[s].add);
	}
}
int main() {
	int ans=0,cur;
  	tot++;
  	cin>>n>>m;
  	int root=1; 
	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
	for (int i=1;i<=n;++i) update(root,1,n,i,i,a[i]);
	for(int i=1,q,x,y;i<=m;i++)
	{   
		scanf("%d%d%d",&q,&x,&y);
		if(q==1)
		{	scanf("%d",&cur);
			update(root,1,n,x,y,cur);
		}
		else
		{	
			cout<<query(1,1,n,x,y,0)<<endl;
		}
	}
    return 0;
}
posted @ 2018-09-17 09:58  Splitor  阅读(932)  评论(1编辑  收藏  举报