bzoj3188 Upit

18 篇文章 0 订阅
17 篇文章 0 订阅
本文介绍了一种使用平衡树处理区间赋值和区间加等差数列问题的方法。通过维护特殊的标记,可以高效地合并区间操作。在实际比赛中,作者由于混淆了不同的标记维护方式而未能正确解决,但在理解了正确的维护方式后,这个问题成为了一个标准模板题。代码展示了如何实现这一数据结构并处理各种操作。
摘要由CSDN通过智能技术生成

题意:

思路:
类似于线段树维护标记。
区间赋值,优先级最高,直接对和进行维护。
区间加等差数列就可以把标记设为 :首项和公差,这样区间加等差数列的标记就能合并了。
再套平衡树就好了。

ops:
第一道比赛中做的平衡树的题。
因为当时状态比较拉跨,并且区间加等差数列的标记和之前一个线段树加等差数列的平方 的标记搞混了,觉得不能做。知道标记的维护方式,那他就成了裸裸的模板题了。

#include<bits/stdc++.h>
using namespace std;
#define ll long long

const int maxn=300010,INF=1e9;

ll n,m;
struct node{
	ll vis[2],v,rnd,siz;
	ll sum;
	ll laz;
	ll fir,sec;
}tree[maxn];

int tot=0,root=0;

void update(int x){
	tree[x].siz=tree[tree[x].vis[0]].siz+tree[tree[x].vis[1]].siz+1;
	tree[x].sum=tree[tree[x].vis[0]].sum+tree[tree[x].vis[1]].sum+tree[x].v;
}

void pushdown1(int x){
	if(tree[x].laz==0)return;
	if(tree[x].vis[0]){
		tree[tree[x].vis[0]].laz=tree[x].laz;
		tree[tree[x].vis[0]].sum=tree[x].laz*tree[tree[x].vis[0]].siz;
		tree[tree[x].vis[0]].v=tree[x].laz;
		tree[tree[x].vis[0]].fir=tree[tree[x].vis[0]].sec=0;
	}
	if(tree[x].vis[1]){
		tree[tree[x].vis[1]].laz=tree[x].laz;
		tree[tree[x].vis[1]].sum=tree[x].laz*tree[tree[x].vis[1]].siz;
		tree[tree[x].vis[1]].v=tree[x].laz;
		tree[tree[x].vis[1]].fir=0;
		tree[tree[x].vis[1]].sec=0;
	}
	
	tree[x].laz=0;
}

void pushdown2(int x){
	if(tree[x].fir==0)return ;
	if(tree[x].vis[0]){
		tree[tree[x].vis[0]].fir+=tree[x].fir;
		tree[tree[x].vis[0]].sec+=tree[x].sec;
		
		int z=tree[tree[x].vis[0]].vis[0];
		tree[tree[x].vis[0]].v+=tree[x].fir+tree[x].sec*(tree[z].siz);
		tree[tree[x].vis[0]].sum+=(2*tree[x].fir+tree[x].sec*(tree[tree[x].vis[0]].siz-1))*tree[tree[x].vis[0]].siz/2;	
	}
	
	if(tree[x].vis[1]){
		ll fir=tree[x].fir+tree[x].sec*(tree[tree[x].vis[0]].siz+1);
		tree[tree[x].vis[1]].fir+=fir;
		tree[tree[x].vis[1]].sec+=tree[x].sec;
		
		int z=tree[tree[x].vis[1]].vis[0];
		tree[tree[x].vis[1]].v+=fir+tree[x].sec*(tree[z].siz);
		
		tree[tree[x].vis[1]].sum+=(2*fir+tree[x].sec*(tree[tree[x].vis[1]].siz-1))*tree[tree[x].vis[1]].siz/2;
	}
	
	tree[x].fir=tree[x].sec=0;
}

int newnode(ll v){
	tot++;
	tree[tot].siz=1;
	tree[tot].v=v;
	tree[tot].rnd=rand();
	tree[tot].sum=v;
	tree[tot].laz=0;tree[tot].fir=0;
	tree[tot].sec=0;
	return tot;
}
int merge(int x,int y){//默认x<y 
	if(!x||!y)return x+y;
	if(tree[x].rnd<tree[y].rnd){
		pushdown1(x);
		pushdown2(x);
		tree[x].vis[1]=merge(tree[x].vis[1],y);
		update(x);
		return x;
	}else{
		pushdown1(y);
		pushdown2(y);
		tree[y].vis[0]=merge(x,tree[y].vis[0]);
		update(y);
		return y;
	}
}
void split2(int now,int k,ll &x,ll &y){//按siz分(找第k大 
	if(!now)x=y=0;
	else {
		pushdown1(now);
		pushdown2(now);
		
		if(k<=tree[tree[now].vis[0]].siz)
			y=now,split2(tree[now].vis[0],k,x,tree[now].vis[0]);
		else x=now,split2(tree[now].vis[1],k-tree[tree[now].vis[0]].siz-1,tree[now].vis[1],y);
		update(now);
	}
}
void insert(int v){
	ll x,y;
	split2(root,v,x,y);
	ll a;
	cin>>a;
	root=merge(merge(x,newnode(a)),y);
}
int main(){
	cin>>n>>m;
	for(int i=1;i<=n;i++)insert(i);
	while(m--){
		ll op,x,y,w;
		cin>>op;
		if(op==1){
			cin>>x>>y>>w;
			ll a,b,c;
			split2(root,y,a,b);
			split2(a,x-1,a,c);
			tree[c].laz=w;
			tree[c].v=w;
			tree[c].sum=w*tree[c].siz;
			root=merge(merge(a,c),b);
		}else if(op==2){
			cin>>x>>y>>w;
			ll a,b,c;
			split2(root,y,a,b);
			split2(a,x-1,a,c);
			tree[c].fir+=w;
			tree[c].v+=w+w*(tree[tree[c].vis[0]].siz);
			tree[c].sec+=w;
			tree[c].sum+=(w+w*(tree[c].siz-1))*tree[c].siz/2;
			root=merge(merge(a,c),b);
		}else if(op==3){
			cin>>w;
			insert(w-1);
		}else{
			cin>>x>>y;
			ll a,b,c;
			split2(root,y,a,b);
			split2(a,x-1,a,c);
			printf("%lld\n",tree[c].sum);
			root=merge(merge(a,c),b);
		}
	}
	return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值