线段树--区间更新模板

练板子题目

Hihocoder #1077

Hihocoder #1078

Hihocoder #1079

Hihocoder #1080

Hihocoder #1116

线段树--区间更新1模板

区间更新的操作为在区间增加权值wei

对应题目POJ - 3468 A Simple Problem with Integers 

#include<iostream>
using namespace std;
/****************************线段树区间更新1模板**************************************/ 
#define ll long long
const int maxn = 100010;
const ll inf =0x3f3f3f3f;
const ll mod=10007;
ll sums;        //全局变量记录区间和 
ll mins;       //全局变量记录区间最值 
ll num[maxn];  //原序列 
struct Brraacks {  //线段树结点 
	ll left,rigth,sum,Min,lazy;    //结点表示的区间[left,right],区间和sum,区间最小值Min,懒惰标记lazy 
} army[maxn * 4];
inline void Build(ll left, ll rigth, ll k) {   //从第k个结点开始,建立区间[left,right]的结点,并初始化这些结点 
	army[k].left = left;
	army[k].rigth = rigth;
	army[k].Min = inf;
	army[k].lazy = 0;
	army[k].sum=0;
	if (left == rigth) return;
	ll mid = (left + rigth) >>1;
	Build(left, mid, k<<1);
	Build(mid + 1, rigth, k<<1|1);
}
inline void Insert(ll wei, ll pos, ll k) {    //从第k个结点开始查找,找到区间[pos,pos]并加上值wei 
	if (army[k].left == army[k].rigth&&army[k].left == pos) {
		army[k].sum = wei;
		army[k].Min = army[k].sum;
		return;
	}
	ll mid = (army[k].left + army[k].rigth) >>1;
	if (pos <= mid)	Insert(wei, pos, k<<1);
	else Insert(wei, pos, k<<1|1);
	army[k].sum = army[k<<1].sum +army[k<<1|1].sum;    //回溯修改第k个结点的sum 
	army[k].Min = min(army[k<<1].Min, army[k<<1|1].Min);
}
inline void pushdown(ll k) {    //将第k个结点的懒惰标记推到他的儿子结点,并更新儿子结点的信息 
	if (army[k].lazy != 0) {
		army[k<<1].sum += (army[k<<1].rigth - army[k<<1].left + 1)*army[k].lazy;
		army[k<<1|1].sum += (army[k<<1|1].rigth - army[k<<1|1].left + 1)*army[k].lazy;
		army[k<<1].lazy += army[k].lazy;
		army[k<<1|1].lazy += army[k].lazy;
		army[k<<1].Min += army[k].lazy;
		army[k<<1|1].Min += army[k].lazy;
		army[k].lazy = 0;
	}
}
 
inline void Update(ll wei, ll l, ll r, ll k) {   //从第k个结点开始查找,找到区间[l,r],区间内的所有点加上wei 
	ll left = army[k].left;
	ll rigth = army[k].rigth;
	if (l <= left&&rigth <= r) {
		army[k].sum += (rigth - left + 1)*wei;
		army[k].lazy += wei;
		army[k].Min += wei;
		return;
	}
	pushdown(k);
	ll mid = (left + rigth) >>1;
	if (l >= mid + 1) Update(wei, l, r, k<<1|1);
	else if (mid >= r) Update(wei, l, r, k<<1);
	else {
		Update(wei, l, r, k<<1);
		Update(wei, l, r, k<<1|1);
	}
	army[k].sum = army[k<<1].sum + army[k<<1|1].sum;
	army[k].Min = min(army[k<<1].Min, army[k<<1|1].Min);
}
inline void Search(ll left, ll rigth, ll k) {   //从第k个结点开始查找,找到区间[left,right],返回区间和(最值) 
	if (left == army[k].left&&rigth == army[k].rigth) {
		sums += army[k].sum;
		mins = min(mins, army[k].Min);
		return;
	}
	pushdown(k);
	ll mid = (army[k].left + army[k].rigth) >>1;
	if (rigth <= mid) Search(left, rigth, k<<1);
	else if (left >= mid + 1) Search(left, rigth, k<<1|1);
	else {
		Search(left, mid, k<<1);
		Search(mid + 1, rigth, k<<1|1);
	}
}
inline void build(ll l,ll r) {   //建立(l,r)的线段树 
	Build(l,r,1);
}
inline void insert(ll wei,ll pos) {   //在pos点加权值wei 
	Insert(wei,pos,1);
}
inline void update(ll wei,ll l,ll r){  //在区间[l,r]内的所有点加上wei 
	Update(wei,l,r,1);
}
inline ll search(ll l,ll r) {     //在区间[l,r]返回区间和(最值) 
	sums=0;
	mins=inf;
	Search(l,r,1);
	//return sums;
    return sums;
}
/****************************线段树区间更新1模板**************************************/ 
int main() {
	int n,q;
	char str[3];
	int l,r;
	ll w;
	while(~scanf("%d %d",&n,&q)) {
		for(int i=1; i<=n; i++) scanf("%lld",&num[i]);
		build(1,n);
		for(int i=1; i<=n; i++)insert(num[i],i);
		for(int i=1; i<=q; i++) {
			scanf("%s",str);
			if(str[0]=='Q') {
				scanf("%d %d",&l,&r);
				ll ans=search(l,r);
				printf("%lld\n",ans);
			} else {
				scanf("%d %d %lld",&l,&r,&w);
				update(w,l,r);
			}
		}
	}
	return 0;
}

线段树--区间更新2模板

区间更新的操作为在区间增加一个权值wei,或者将区间的权值权值全部设置为wei

对应题目Hihocoder #1080 : 更为复杂的买卖房屋姿势

#include<iostream>
#include<map>
#include<algorithm>
#include<cstring>
using namespace std;
/**********************线段树区间更新模板2**************************************************/ 
#define ll long long
const int maxn = 100010;
const ll inf =0x3f3f3f3f;
const ll mod=10007;
ll sums;        //全局变量记录区间和
ll mins;       //全局变量记录区间最值
ll num[maxn<<1];  //原序列
struct Brraacks {  //线段树结点
	ll left,rigth,sum,Min,lazy,flag;    //结点表示的区间[left,right],区间和sum,区间最小值Min,懒惰标记lazy
} army[maxn * 4];
inline void Build(ll left, ll rigth, ll k) {   //从第k个结点开始,建立区间[left,right]的结点,并初始化这些结点
	army[k].left = left;
	army[k].rigth = rigth;
	army[k].Min = inf;
	army[k].lazy = 0;
	army[k].sum=0;
	army[k].flag=0;
	if (left == rigth) return;
	ll mid = (left + rigth) >>1;
	Build(left, mid, k<<1);
	Build(mid + 1, rigth, k<<1|1);
}
inline void Insert(ll wei, ll pos, ll k) {    //从第k个结点开始查找,找到区间[pos,pos]并加上值wei
	if (army[k].left == army[k].rigth&&army[k].left == pos) {
		army[k].sum = wei;
		army[k].Min = army[k].sum;
		return;
	}
	ll mid = (army[k].left + army[k].rigth) >>1;
	if (pos <= mid)	Insert(wei, pos, k<<1);
	else Insert(wei, pos, k<<1|1);
	army[k].sum = army[k<<1].sum +army[k<<1|1].sum;    //回溯修改第k个结点的sum
	army[k].Min = min(army[k<<1].Min, army[k<<1|1].Min);
}
inline void pushdown(ll k) {    //将第k个结点的懒惰标记推到他的儿子结点,并更新儿子结点的信息
	if (army[k].lazy != 0) {
		if(army[k].flag) {
			army[k<<1].sum = (army[k<<1].rigth - army[k<<1].left + 1)*army[k].lazy;
			army[k<<1|1].sum = (army[k<<1|1].rigth - army[k<<1|1].left + 1)*army[k].lazy;
			army[k<<1].lazy = army[k].lazy;
			army[k<<1|1].lazy = army[k].lazy;
			army[k<<1].Min = army[k].lazy;
			army[k<<1|1].Min = army[k].lazy;
			army[k].lazy = 0;
			army[k<<1].flag=1;
			army[k<<1|1].flag=1;
			army[k].flag=0;
		} else {
			if(army[k<<1].flag)	pushdown(k<<1);
			if(army[k<<1|1].flag) pushdown(k<<1|1);
			army[k<<1].sum += (army[k<<1].rigth - army[k<<1].left + 1)*army[k].lazy;
			army[k<<1|1].sum += (army[k<<1|1].rigth - army[k<<1|1].left + 1)*army[k].lazy;
			army[k<<1].lazy += army[k].lazy;
			army[k<<1|1].lazy += army[k].lazy;
			army[k<<1].Min += army[k].lazy;
			army[k<<1|1].Min += army[k].lazy;
			army[k].lazy = 0;
		}
	}
}

inline void Update(bool flag,ll wei, ll l, ll r, ll k) {   //从第k个结点开始查找,找到区间[l,r],falg为0则区间内的所有点加上wei,flag为1则将区间内的所有点设置为wei
	ll left = army[k].left;
	ll rigth = army[k].rigth;
	if (l <= left&&rigth <= r) {
		if(flag) {
			army[k].sum = (rigth - left + 1)*wei;
			army[k].lazy = wei;
			army[k].Min = wei;
			army[k].flag=1;
			return;
		} else {
			army[k].sum += (rigth - left + 1)*wei;
			army[k].lazy += wei;
			army[k].Min += wei;
			return;
		}
	}
	pushdown(k);
	ll mid = (left + rigth) >>1;
	if (l >= mid + 1) Update(flag,wei, l, r, k<<1|1);
	else if (mid >= r) Update(flag,wei, l, r, k<<1);
	else {
		Update(flag,wei, l, r, k<<1);
		Update(flag,wei, l, r, k<<1|1);
	}
	army[k].sum = army[k<<1].sum + army[k<<1|1].sum;
	army[k].Min = min(army[k<<1].Min, army[k<<1|1].Min);
}

inline void Search(ll left, ll rigth, ll k) {   //从第k个结点开始查找,找到区间[left,right],返回区间和(最值)
	if (left == army[k].left&&rigth == army[k].rigth) {
		sums += army[k].sum;
		mins = min(mins, army[k].Min);
		return;
	}
	pushdown(k);
	ll mid = (army[k].left + army[k].rigth) >>1;
	if (rigth <= mid) Search(left, rigth, k<<1);
	else if (left >= mid + 1) Search(left, rigth, k<<1|1);
	else {
		Search(left, mid, k<<1);
		Search(mid + 1, rigth, k<<1|1);
	}
}
inline void build(ll l,ll r) {   //建立(l,r)的线段树
	Build(l,r,1);
}
inline void insert(ll wei,ll pos) {   //在pos点加权值wei
	Insert(wei,pos,1);
}
inline void update(ll wei,ll l,ll r,bool flag) { //flag=0则在区间[l,r]内的所有点加上wei
	Update(flag,wei,l,r,1);                      //flag=1则在将区间[l,r]内的所有点设置为wei
}
inline ll search(ll l,ll r) {     //在区间[l,r]返回区间和(最值)
	sums=0;
	mins=inf;
	Search(l,r,1);
	//return sums;
	return sums;
}
/**********************线段树区间更新模板2**************************************************/ 
int L[maxn],R[maxn];
bool vis[maxn];
map<int,int>maps;
void debug(int n,int m) {
	for(int i=1;i<=n;i++){
		printf("%d %d\n",maps[L[i]],maps[R[i]]);
	}
	for(int i=1; i<=m; i++) {
		ll sum_=search(i,i);
		printf("%lld ",sum_);
	}
	cout<<endl;
}

int  Hash(int n) {
	sort(num+1,num+2*n+1);
	int tol=0;
	for(int i=1; i<=n<<1; i++) {
		if(maps[num[i]]==0)
			maps[num[i]]=++tol;
	}
	return tol;
}
int main() {
	int n,_L;
	while(~scanf("%d %d",&n,&_L)) {
		for(int i=1; i<=n; i++) {
			scanf("%d %d",&L[i],&R[i]);
			num[i]=L[i];
			num[n+i]=R[i];
		}
		memset(vis,0,sizeof(vis));
		maps.clear();
		int m=Hash(n);
		build(1,m);
		int cnt=0;
		for(int i=1; i<=n; i++) {
			int l=maps[L[i]]+1;
			int r=maps[R[i]];
			update(i,l,r,1);
		}
		//debug(n,m);
		vis[0]=1;
		for(int i=1; i<=m; i++) {
			ll tmp=search(i,i);
			if(vis[tmp]==0) {
				cnt++;
				vis[tmp]=1;
			}
		}
		printf("%d\n",cnt);
	}
	return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值