线段树练习

背景

  连着几天做计算几何,表示整个人都快要疯掉了。。昨天晚上看动漫+刷水题放松了一下

题目

  http://codevs.cn/problem/1082/

  http://codevs.cn/problem/4919/

  http://codevs.cn/problem/4927/

题解

  第一题,线段树模板上

  第二题,用w[i]表示这个节点所表示的区间里有多少除7余i的

  第三题,各种乱搞,注意双标记的处理顺序,如果给一个有add标记的点加上set标记,则add标记要置零,对于有两个标记的先set再add。

代码

T1

//线段树练习3 
#include <cstdio>
#include <algorithm>
#define maxn 200010
#define ll long long
using namespace std;
struct segtree
{
	ll l, r, d, w;
	segtree *lch, *rch;
}*root;
ll N, a[maxn];
void pushdown(segtree *pos)
{
	pos->w+=pos->d*(pos->r-pos->l+1);
	if(pos->lch)pos->lch->d+=pos->d;
	if(pos->rch)pos->rch->d+=pos->d;
	pos->d=0;
}
void add(segtree *pos, ll l, ll r, ll w)
{
	pushdown(pos);
	ll mid=pos->l+pos->r>>1;
	if(l<=pos->l and r>=pos->r){pos->d+=w;return;}
	if(l<=mid)add(pos->lch,l,r,w),pos->w+=(min(mid,r)-max(l,pos->l)+1)*w;
	if(r>mid)add(pos->rch,l,r,w),pos->w+=(min(r,pos->r)-max(l,mid+1)+1)*w;
}
ll sum(segtree *pos, ll l, ll r)
{
	pushdown(pos);
	ll mid=pos->l+pos->r>>1, ans=0;
	if(l<=pos->l and r>=pos->r)return pos->w;
	if(l<=mid){ans+=sum(pos->lch,l,r);}
	if(r>mid){ans+=sum(pos->rch,l,r);}
	return ans;
}
void build(segtree *pos, ll l, ll r)
{
	ll mid=l+r>>1;
	pos->l=l,pos->r=r;
	if(l==r)pos->w=a[l];
	else
	{
		build(pos->lch=new segtree,l,mid);
		build(pos->rch=new segtree,mid+1,r);
		pos->w=pos->lch->w+pos->rch->w;
	}
}
int main()
{
	ll i, l, r, w, q, type;
	scanf("%lld",&N);
	for(i=1;i<=N;i++)scanf("%lld",a+i);
	build(root=new segtree,1,N);
	scanf("%lld",&q);
	for(i=1;i<=q;i++)
	{
		scanf("%lld%lld%lld",&type,&l,&r);
		if(type==2)printf("%lld\n",sum(root,l,r));
		else{scanf("%lld",&w);add(root,l,r,w);}
	}
	return 0;
}

T2

//线段树练习4
#include <cstdio>
#include <algorithm>
#define maxn 100010
using namespace std;
struct node
{
	int l, r, w[10], d;
	node *lch, *rch;
}*root;
int N, a[maxn];
void pushdown(node *pos)
{
	int i, w[10];
	for(i=0;i<7;i++)w[(i+pos->d)%7]=pos->w[i];
	for(i=0;i<7;i++)pos->w[i]=w[i];
	if(pos->l!=pos->r)pos->lch->d+=pos->d,pos->rch->d+=pos->d;
	pos->d=0;
}
void update(node *pos)	//保证祖先到儿子信息正确才能调用 
{
	int i;
	if(pos->l==pos->r)return;
	pushdown(pos->lch),pushdown(pos->rch);
	for(i=0;i<7;i++)pos->w[i]=pos->lch->w[i]+pos->rch->w[i];
}
void add(node *pos, int l, int r, int w)
{
	pushdown(pos);
	int i, mid=pos->l+pos->r>>1;
	if(l<=pos->l and r>=pos->r)pos->d+=w;
	else
	{
		if(l<=mid)add(pos->lch,l,r,w);
		if(r>mid)add(pos->rch,l,r,w);
		update(pos);
	}
}
int sum(node *pos, int l, int r)
{
	pushdown(pos);
	int mid=pos->l+pos->r>>1, ans=0;
	if(l<=pos->l and r>=pos->r)return pos->w[0];
	if(l<=mid)ans+=sum(pos->lch,l,r);
	if(r>mid)ans+=sum(pos->rch,l,r);
	return ans;
}
void build(node *pos, int l, int r)
{
	int mid=l+r>>1;
	pos->l=l,pos->r=r;
	if(l==r){pos->w[a[l]%7]++;return;}
	build(pos->lch=new node,l,mid);
	build(pos->rch=new node,mid+1,r);
	update(pos);
}
int main()
{
	int i, q, l, r, w, x;
	char s[100];
	scanf("%d",&N);
	for(i=1;i<=N;i++)scanf("%d",a+i);
	build(root=new node,1,N);
	scanf("%d",&q);
	for(i=1;i<=q;i++)
	{
		scanf("%s%d%d",s,&l,&r);
		if(s[0]=='a')
		{
			scanf("%d",&w);
			add(root,l,r,w%7);
		}
		else printf("%d\n",sum(root,l,r));
	}
	return 0;
}

T3

//线段树练习5
#include <cstdio>
#include <algorithm>
#define maxn 100010
#define ll long long
#define inf ((long long)1<<60)
using namespace std;
struct node
{
	ll l, r, summ, minn, maxx, sett, add;
	node *lch, *rch;
}*root;
ll a[maxn], N;
void pushdown(node *p)
{
	if(p->sett!=-1)
	{
		p->minn=p->maxx=p->sett;
		p->summ=(p->r-p->l+1)*p->sett;
		if(p->lch)
			p->lch->sett=p->sett,p->rch->sett=p->sett,p->lch->add=0,p->rch->add=0;
		p->sett=-1;
	}
	if(p->add)
	{
		p->minn+=p->add,p->maxx+=p->add;
		p->summ+=(p->r-p->l+1)*p->add;
		if(p->lch)p->lch->add+=p->add,p->rch->add+=p->add;
		p->add=0;
	}
}
void update(node *p)
{
	if(!p->lch)return;
	pushdown(p->lch),pushdown(p->rch);
	p->minn=min(p->lch->minn,p->rch->minn);
	p->maxx=max(p->lch->maxx,p->rch->maxx);
	p->summ=p->lch->summ+p->rch->summ;
}
void add(node *p, ll l, ll r, ll w)
{
	pushdown(p);
	ll mid=p->l+p->r>>1;
	if(l<=p->l and r>=p->r)p->add+=w;
	else
	{
		if(l<=mid)add(p->lch,l,r,w);
		if(r>mid)add(p->rch,l,r,w);
		update(p);
	}
}
void sett(node *p, ll l, ll r, ll w)
{
	pushdown(p);
	ll mid=p->l+p->r>>1;
	if(l<=p->l and r>=p->r)p->sett=w;
	else
	{
		if(l<=mid)sett(p->lch,l,r,w);
		if(r>mid)sett(p->rch,l,r,w);
		update(p);
	}
}
ll solve(node *p, ll l, ll r, ll type)
{
	pushdown(p);
	ll mid=p->l+p->r>>1, ans1=-1, ans2=-1;
	if(l<=p->l and r>=p->r)
	{
		if(type==1)return p->summ;
		if(type==2)return p->maxx;
		if(type==3)return p->minn;
	}
	if(l<=mid)ans1=solve(p->lch,l,r,type);
	if(r>mid)ans2=solve(p->rch,l,r,type);
	if(type==1)return max(ans1,(ll)0)+max(ans2,(ll)0);
	if(type==2)return max(ans1,ans2);
	if(type==3)return min(ans1==-1?inf:ans1,ans2==-1?inf:ans2);
}
void build(node *p, ll l, ll r)
{
	p->l=l,p->r=r;p->sett=-1;
	if(l==r){p->summ=p->maxx=p->minn=a[l];return;}
	ll mid=l+r>>1;
	build(p->lch=new node,l,mid);
	build(p->rch=new node,mid+1,r);
	update(p);
}
int main()
{
	ll i, m, l, r, w;
	char type[100], c;
	scanf("%lld%lld",&N,&m);
	for(i=1;i<=N;i++)scanf("%lld",a+i);
	build(root=new node,1,N);
	for(i=1;i<=m;i++)
	{
		scanf("%s%lld%lld",type,&l,&r);c=type[1];
		switch(c)
		{
			case 'u':printf("%lld\n",solve(root,l,r,1));break;
			case 'a':printf("%lld\n",solve(root,l,r,2));break;
			case 'i':printf("%lld\n",solve(root,l,r,3));break;
			case 'd':scanf("%lld",&w);add(root,l,r,w);break;
			case 'e':scanf("%lld",&w);sett(root,l,r,w);
		}
	}
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值