hpu--1721(离散化)



1721: 感恩节KK专场——雪人的高度

时间限制: 1 Sec   内存限制: 128 MB
提交: 88   解决: 39
[ 提交][ 状态][ 讨论版]

题目描述

大雪过后,KK决定在春秋大道的某些区间上堆雪人。现在KK遇到了一道统计雪人高度的难题,请你帮帮他吧。注:KK堆雪人前春秋大道上是没有雪人的即所有位置雪人高度为0。

输入

给定一个整数t,表示有t(t<=5)组测试数据。每组测试数据有两个整数N(1<=N<=200000),表示N次操作。

操作分四种:
   U1 x y v   [x, y]位置的雪人高度减v
 

   U2 x y v   [x, y]位置的雪人高度加v

   Q1 x y     查询[x, y]之间雪人的最大高度
   
Q2 x y     查询[x, y]之间雪人的最小高度

   注: (|x|, |y|<=2^30, |v|<=100)

   若上面的操作使某个位置的雪人高度为负,我们认为这种情况是合法的。

输出

对每个查询输出结果,结果占一行。结果保证不会超int。

样例输入

12U2 -1000 1000 1Q1 1000 10001

样例输出

1


解题思路:第一道线段树离散化,模仿了大神的方法,对离散化操作有了一丢丢的的了解。

代码如下:
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
struct stu{
	int l,r,maxn,minn,c;
	int mid(){
		return (l+r)>>1;
	}
};
stu node[200010<<3];
int  x[200000+10];
int  y[200000+10];
int  v[200000+10];
int mark[200000+10];
int li[200010<<2];
void build(int i,int l,int r){
	node[i].l=l;
	node[i].r=r;
	node[i].maxn=0;
	node[i].minn=0;
	node[i].c=0;
	if(r==l){
	    return ;
	}
	int m=node[i].mid();
	build(i<<1,l,m);
	build(i<<1|1,m+1,r);
}
void PUTUP(int i){
	node[i].maxn=max(node[i<<1].maxn,node[i<<1|1].maxn);
	node[i].minn=min(node[i<<1].minn,node[i<<1|1].minn);
}
void PUTDOWN(int i){
	if(node[i].c){
		node[i<<1].c+=node[i].c;
		node[i<<1|1].c+=node[i].c;
		node[i<<1].maxn+=node[i].c;
		node[i<<1].minn+=node[i].c;
		node[i<<1|1].maxn+=node[i].c;
		node[i<<1|1].minn+=node[i].c;
		node[i].c=0;
	}
}
void updata(int i,int l,int r,int v){
	if(node[i].l==l&&node[i].r==r){
		node[i].c+=v;
		node[i].maxn+=v;
		node[i].minn+=v;
		return ;
	}
	PUTDOWN(i);
	int m=node[i].mid();
	if(r<=m)updata(i<<1,l,r,v);
	else{
		if(l>m)updata(i<<1|1,l,r,v);
		else{
			updata(i<<1,l,m,v);
			updata(i<<1|1,m+1,r,v);
		}
	}
	PUTUP(i);
}
int query(int i,int l,int r,int w){
	if(node[i].l==l&&node[i].r==r){
		if(w==1)
		return node[i].maxn;
		else return node[i].minn;
	}
	PUTDOWN(i);
	int m=node[i].mid();
	if(r<=m) return query(i<<1,l,r,w);
	else{
		if(l>m)return query(i<<1|1,l,r,w);
		else{
			if(w==1)
			return max(query(i<<1,l,m,w),query(i<<1|1,m+1,r,w));
			else return min(query(i<<1,l,m,w),query(i<<1|1,m+1,r,w));
		}
	}
	
}
int find(int l,int r,int x){
	while(l<=r)
    {
        int mid=(l+r)>>1;
        if(li[mid]==x)
            return mid;
        if(li[mid]>x)
            r=mid-1;
        else
            l=mid+1;
    }
}
int main(){
    int t,k,n;
    char s[5];
    scanf("%d",&t);
    while(t--){
    	k=0;
    	scanf("%d",&n);
    	for(int i=0;i<n;i++){
    		scanf("%s",s);
    		if(strcmp(s,"U1")==0){
    			mark[i]=1;
    			scanf("%d%d%d",&x[i],&y[i],&v[i]);
    		}
    		else if(strcmp(s,"U2")==0){
    			mark[i]=2;
    			scanf("%d%d%d",&x[i],&y[i],&v[i]);
    			
    		}
    		else if(strcmp(s,"Q1")==0){
    			mark[i]=3;
    			scanf("%d%d",&x[i],&y[i]);
    		}
    		else{
    			mark[i]=4;
    			scanf("%d%d",&x[i],&y[i]);
    		}
    		li[++k]=x[i];
    		li[++k]=y[i];
    		
    	}
    	sort(li+1,li+k+1);
    	//printf("%d %d %d %d",li[1],li[2],li[3],li[4]);
    	int j=2;
    	for(int i=2;i<=k;i++){
    		if(li[i]!=li[i-1]){
    			li[j++]=li[i];
    		}
    	
    	}
    	build(1,1,j-1);
    	for(int i=0;i<n;i++){
    		int l=find(1,j-1,x[i]);
    		int r=find(1,j-1,y[i]);
    		if(l>r){
    			int tem=l;
                l=r;
                r=tem;
    		}
    			if(mark[i]==1){
    			updata(1,l,r,-v[i]);
    		}
    		else if(mark[i]==2){
    			updata(1,l,r,v[i]);
    		}
    		else if(mark[i]==3){
    			printf("%d\n",query(1,l,r,1));
    		}
    		else{
    			printf("%d\n",query(1,l,r,2));
    		}
    		
    	}
    }
	return 0;
}




1721: 感恩节KK专场——雪人的高度

时间限制: 1 Sec   内存限制: 128 MB
提交: 88   解决: 39
[ 提交][ 状态][ 讨论版]

题目描述

大雪过后,KK决定在春秋大道的某些区间上堆雪人。现在KK遇到了一道统计雪人高度的难题,请你帮帮他吧。注:KK堆雪人前春秋大道上是没有雪人的即所有位置雪人高度为0。

输入

给定一个整数t,表示有t(t<=5)组测试数据。每组测试数据有两个整数N(1<=N<=200000),表示N次操作。

操作分四种:
   U1 x y v   [x, y]位置的雪人高度减v
 

   U2 x y v   [x, y]位置的雪人高度加v

   Q1 x y     查询[x, y]之间雪人的最大高度
   
Q2 x y     查询[x, y]之间雪人的最小高度

   注: (|x|, |y|<=2^30, |v|<=100)

   若上面的操作使某个位置的雪人高度为负,我们认为这种情况是合法的。

输出

对每个查询输出结果,结果占一行。结果保证不会超int。

样例输入

12U2 -1000 1000 1Q1 1000 10001

样例输出

1
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值