UVa 11992

典型线段树,由于是初学,写错了很多很多东西

#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#include <vector>
#include <deque>
#include <algorithm>
#include <list>
#include <map>
#include <set>
#include <queue>
#include <stack>
#define REP(i,n) for(int i=0;i<(n);i++)
#define REP1(i,n) for(int i=1;i<=(n);i++)
#define FOR(i,a,b) for (int i=(a);i<=(b);i++)
#define CLR(x,n) memset(x,n,sizeof(x))
#define PN printf("\n")
#define read(x) scanf("%d",&x)
#define read2(x,y) scanf("%d%d",&x,&y)
#define read3(x,y,z) scanf("%d%d%d",&x,&y,&z)
#define write(x) printf("%d",x)
#define write1(x) printf("%d ",x)
#define writeln(x) printf("%d\n",x)
#define write2(x,y) printf("%d %d",x,y)
#define writeln2(x,y) printf("%d %d\n",x,y)
#define write3(x,y,z) printf("%d %d %d",x,y,z)
#define writeln3(x,y,z) printf("%d %d %d\n",x,y,z)
#define delta 1e-5
#define INF 0x7FFFFFFF
using namespace std;
/*
add出现负数,原来是pushdown里把addv设成了-1
此外 pushdown中打错一个setv[2*o]=-1; 
pushdown中出现致命错误 addv[2*o]=addv[2*o+1]=addv[o] 应该用+= 
还是不对 add操作边界条件进去应该addv[o]+= 而不是=  
query的add也要注意
又写错一处 setv[o]>=0 里面的 运算 应该要带max min 
对拍的时候发现一处错误 maintain中要把信息清零 
碰到致命问题 把1-8set为1 再 add 8 8 1 那么查8的时候会出问题
只好在add中仿照 set进行pushdown 
拍了好久 又发现问题 query里即使setv>=0也要考虑add
又有问题 add多次再set值会很大 因为set往下传的时候下面的add值还在 
所以如果setv>0要把儿子的addv清零 
*/ 
const int maxn=1<<17;
int r,c,m,op,_sum,_min,_max,x1,x2,Y1,Y2,v;
int addv[22][2*maxn],sumv[22][2*maxn],maxv[22][2*maxn],minv[22][2*maxn],setv[22][2*maxn];

void query(int t,int o,int l,int r,int add){
	if (setv[t][o]>=0){
		_sum+=(setv[t][o]+addv[t][o])*(min(r,Y2)-max(l,Y1)+1);
		_sum+=add*(min(r,Y2)-max(l,Y1)+1);
		_max=max(_max,setv[t][o]+addv[t][o]+add);
		_min=min(_min,setv[t][o]+addv[t][o]+add);
	}else if (Y1<=l && r<=Y2){
		_sum+=sumv[t][o]+add*(r-l+1);
		_max=max(_max,maxv[t][o]+add);
		_min=min(_min,minv[t][o]+add);
	}else {
		int m=(l+r)/2;
		if (Y1<=m) query(t,2*o,l,m,add+addv[t][o]);
		if (Y2>m) query(t,2*o+1,m+1,r,add+addv[t][o]);
	}
}
void maintain(int t,int o,int l,int r){
	sumv[t][o]=maxv[t][o]=minv[t][o]=0;
	if (r>l){
		sumv[t][o]=sumv[t][2*o]+sumv[t][2*o+1];
		maxv[t][o]=max(maxv[t][2*o],maxv[t][2*o+1]);
		minv[t][o]=min(minv[t][2*o],minv[t][2*o+1]);
	}
	if (setv[t][o]>=0) {
		sumv[t][o]=setv[t][o]*(r-l+1);
		maxv[t][o]=setv[t][o];
		minv[t][o]=setv[t][o];
	}
	sumv[t][o]+=addv[t][o]*(r-l+1); maxv[t][o]+=addv[t][o];minv[t][o]+=addv[t][o];
}

void pushdown(int t,int o){
	if (setv[t][o]>=0){
		setv[t][2*o]=setv[t][2*o+1]=setv[t][o];
		setv[t][o]=-1;
		addv[t][2*o]=addv[t][2*o+1]=0;
	}
	
	addv[t][2*o]+=addv[t][o];
	addv[t][2*o+1]+=addv[t][o];
	addv[t][o]=0;
}
void add(int t,int o,int l,int r){
	if(Y1<=l && r<=Y2)
	addv[t][o]+=v;
	else {
		pushdown(t,o);
		int m=l+(r-l)/2;
		if (Y1<=m) add(t,2*o,l,m);else maintain(t,2*o,l,m);
		if (m<Y2) add(t,2*o+1,m+1,r);else maintain(t,2*o+1,m+1,r);
	}
	maintain(t,o,l,r);
}

void set1(int t,int o,int l,int r){
	if (Y1<=l && r<=Y2){
		setv[t][o]=v;
		addv[t][o]=0;
	}
	else {
		pushdown(t,o);
		int m=l+(r-l)/2;
		if (Y1<=m) set1(t,2*o,l,m); else maintain(t,2*o,l,m);
		if (Y2>m) set1(t,2*o+1,m+1,r); else maintain(t,2*o+1,m+1,r);
	}
	maintain(t,o,l,r);
}
void print(){
	REP(i,2*maxn)printf("%d %d %d %d %d %d\n",i,sumv[6][i],maxv[6][i],minv[6][i],addv[6][i],setv[6][i]);
}
 
int main(){
	read3(r,c,m);CLR(setv,-1);CLR(addv,0);
	REP(i,m){
		read(op);
		if (op==1){
			scanf("%d%d%d%d%d",&x1,&Y1,&x2,&Y2,&v);
			FOR(i,x1,x2)add(i,1,1,maxn);
		}else if (op==2){
			scanf("%d%d%d%d%d",&x1,&Y1,&x2,&Y2,&v);
			FOR(i,x1,x2)set1(i,1,1,maxn);
		}else {
			scanf("%d%d%d%d",&x1,&Y1,&x2,&Y2);
			_sum=0;_max=-INF;_min=INF;
			FOR(i,x1,x2){query(i,1,1,maxn,0);}
			printf("%d %d %d\n",_sum,_min,_max); 
			
		}
		//print();PN;
	}
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值