bzoj 1699

这道题,由于细节不注意,挂了,另一方面,也是由于对线段树的理解不够透彻,线段树是将一个个的大区间分层一个一个的小区间,而这个大区间很可能会跨越很多很多小区间,但是这个大区间的很多值都与小区间有关,而不是相同,例如最值的差,举个例子:
区间[1,8]分为区间[1,4](区间1)[5,8])(区间2),其中区间1的最值分别为 4,8;区间2的最值分别为2,1;那么如果直接分开求(分别为4,1),在比大小,得出总区间的最值得差为4,而实际上是8 - 1 = 7;
这就是下面这个代码错误的原因

#include<bits/stdc++.h>
using namespace std;
const int maxxn = 180000 * 4 + 20;
const int maxx = 180010;

int n,qq;
int a[maxx];
struct node {
	int l,r,dat,mn;
};
node t[maxxn];

inline int Read () {
	int xx = 0;
	int ff = 1;
	char ch = getchar();
	while (ch > '9' || ch < '0') {
		if (ch == '-') ff = -1;
		ch = getchar();
	}
	while (ch <= '9' && ch >= '0') {
		xx = (xx << 1) + (xx << 3) + (ch ^ 48);
		ch = getchar();
	}
	return xx * ff;
}
inline void WW (int x) {
	if (x == 0) {
		putchar('0');
		putchar(10);
		return ;
	}
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	int num = 0;
	char ch[19];
	while (x != 0) {
		ch[++num] = (x % 10) + '0';
		x /= 10;
	}
	while (num != 0) {
		putchar(ch[num--]);
	}
	putchar(10);
	return ;
}
void build (int p,int l,int r) {
	t[p].l = l; t[p].r = r;
	if (l == r) {
		t[p].dat = a[l];
		t[p].mn = a[l];
		return ;
	}
	int mid = l + r >> 1;
	build(p << 1,l,mid);
	build(p << 1 | 1,mid + 1,r);
	t[p].dat = max(t[p << 1].dat,t[p << 1 | 1].dat);
	t[p].mn = min(t[p << 1].mn,t[p << 1 | 1].mn);
	return ;
}
inline int ass (int p,int l,int r) {
	if (t[p].l >= l && t[p].r <= r) {
		return (t[p].dat - t[p].mn);//这里是两个分区间的最值的差,而不是整个区间的 
	}
	int mid = t[p].l + t[p].r >> 1;
	int ans = -99999;
	if (l <= mid) ans = max(ans,ass(p << 1,l,r));
	if (r > mid) ans = max(ans,ass(p << 1 | 1,l,r));
	return ans;
}

int main () {
	n = Read(); qq = Read();
	for (int i = 1;i <= n;i++) {
		a[i] = Read();
	}
	build(1,1,n);
	for (int i = 1;i <= qq;i++) {
		int aa = Read(); int bb = Read();
		WW(ass(1,aa,bb));
	}
	return 0;
}

正解

#include<bits/stdc++.h>
using namespace std;
const int maxxn = 180000 * 4 + 20;
const int maxx = 180010;

int n,qq;
int a[maxx];
struct node {
	int l,r,dat,mn;
};
node t[maxxn];

inline int Read () {
	int xx = 0;
	int ff = 1;
	char ch = getchar();
	while (ch > '9' || ch < '0') {
		if (ch == '-') ff = -1;
		ch = getchar();
	}
	while (ch <= '9' && ch >= '0') {
		xx = (xx << 1) + (xx << 3) + (ch ^ 48);
		ch = getchar();
	}
	return xx * ff;
}
inline void WW (int x) {
	if (x == 0) {
		putchar('0');
		putchar(10);
		return ;
	}
	if (x < 0) {
		putchar('-');
		x = -x;
	}
	int num = 0;
	char ch[19];
	while (x != 0) {
		ch[++num] = (x % 10) + '0';
		x /= 10;
	}
	while (num != 0) {
		putchar(ch[num--]);
	}
	putchar(10);
	return ;
}
void build (int p,int l,int r) {
	t[p].l = l; t[p].r = r;
	if (l == r) {
		t[p].dat = a[l];
		t[p].mn = a[l];
		return ;
	}
	int mid = l + r >> 1;
	build(p << 1,l,mid);
	build(p << 1 | 1,mid + 1,r);
	t[p].dat = max(t[p << 1].dat,t[p << 1 | 1].dat);
	t[p].mn = min(t[p << 1].mn,t[p << 1 | 1].mn);
	return ;
}
inline int ass1 (int p,int l,int r) {
	if (t[p].l >= l && t[p].r <= r) {
		return t[p].dat;
	}
	int mid = t[p].l + t[p].r >> 1;
	int ans = -99999;
	if (l <= mid) ans = max(ans,ass1(p << 1,l,r));
	if (r > mid) ans = max(ans,ass1(p << 1 | 1,l,r));
	return ans;
}
inline int ass2 (int p,int l,int r) {
	if (t[p].l >= l && t[p].r <= r) {
		return t[p].mn;
	}
	int mid = t[p].l + t[p].r >> 1;
	int ans = 9999999;
	if (l <= mid) ans = min(ans,ass2(p << 1,l,r));
	if (r > mid) ans = min(ans,ass2(p << 1 | 1,l,r));
	return ans;
}

int main () {
	n = Read(); qq = Read();
	for (int i = 1;i <= n;i++) {
		a[i] = Read();
	}
	build(1,1,n);
	for (int i = 1;i <= qq;i++) {
		int aa = Read(); int bb = Read();
		WW(ass1(1,aa,bb) - ass2(1,aa,bb));
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值