吉老师线段树 hdu5306

吉老师线段树

这个是干啥的?
其实就是个线段树,我也不知道为什么叫吉老师线段树
简单例题:hdu5306
三种操作:
0 l r x 把 l ~ r 区间里大于 x 的数变成 x
1 l r 求 l ~ r 区间里的最大值
2 l r 求 l ~ r 区间和
题解:
线段树里记一个最大值max、最大值的个数num、次大值max2、区间和sum。
查询很好查询,主要是维护
更新:
如果当前区间最大值小于等于x 那么就不用修改。
如果当前区间最大值 > x > 次大值 那么只用把最大值改为x、记tag、更新和就好
其他情况继续往下走、
但是时间复杂度???为什么我感觉很高。
想一哈: 最坏情况,把 1 ~ n 变成0 得遍历一整棵树??
有大佬说:最坏复杂度是 n乘logn方。
大概就是这了。
hdu5306
wa死我了啊!!我好粗心,
wa的地方:
次大值更新错了。
longlong。
update里判断往左往右更新,
没往下更新查询tag。
代码:

#include
#include
using namespace std;
const int maxn = 1e6+2;
int a[maxn];
typedef long long ll;
struct Node
{
	int max,max2,tag,l,r,num;
	ll sum;
}node[maxn<<2];
void up(int no)
{
	node[no].sum = node[no<<1].sum + node[no<<1|1].sum;
	if(node[no<<1].max == node[no<<1|1].max)
	{
		node[no].max = node[no<<1].max;
		node[no].num = node[no<<1].num + node[no<<1|1].num;
		node[no].max2 = max(node[no<<1].max2,node[no<<1|1].max2);
	}
	else
	{
		node[no].max = max(node[no<<1].max,node[no<<1|1].max);
		node[no].max2 = max(node[no<<1].max2,max(node[no<<1|1].max2,min(node[no<<1].max,node[no<<1|1].max)));
		node[no].num = (node[no<<1].max > node[no<<1|1].max ? node[no<<1].num : node[no<<1|1].num);
	}
}

void build(int l,int r,int no)
{
	node[no].l = l;
	node[no].r = r;
	node[no].tag = -1;
	if(l == r)
	{
		node[no].num = 1;
		node[no].max = a[l];
		node[no].max2 = -1;
		node[no].sum = a[l];
		return;
	}
	int mid = l + r >> 1;
	build(l,mid,no<<1);
	build(mid+1,r,no<<1|1);
	up(no);
}
void change(int no,int num)
{
	if(num >= node[no].max) return;
	if(num > node[no].max2)
	{
		node[no].sum -= 1ll * node[no].num * (node[no].max- num);
		node[no].max = num;
		node[no].tag = num;
		return;
	}
}
void down(int no)
{
	change(no<<1,node[no].tag);
	change(no<<1|1,node[no].tag);
	node[no].tag = -1;
}

void update(int l,int r,int num,int no)
{
	if(node[no].l >= l && node[no].r <= r)
	{
		if(num >= node[no].max) return;
		if(num > node[no].max2)
		{
			node[no].sum -= 1ll * node[no].num * (node[no].max - num);
			node[no].max = num;
			node[no].tag = num;
			return;
		}
		int mid = node[no].l + node[no].r >> 1;
		update(node[no].l,mid,num,no<<1);
		update(mid + 1,node[no].r,num,no<<1|1);
		up(no);
		return;
	}
	if(node[no].tag != -1)
		down(no);
	int mid = node[no].l + node[no].r >> 1;
	if(l <= mid)
		update(l,r,num,no<<1);
	if(r > mid)
		update(l,r,num,no<<1|1);
	up(no);
}
int query1(int l,int r,int no)
{
	if(node[no].l > r || node[no].r < l)
		return -1;
	if(node[no].l >= l && node[no].r <= r)
		return node[no].max;
	if(node[no].tag != -1)
		down(no);
	return max(query1(l,r,no<<1),query1(l,r,no<<1|1));
}

ll query2(int l,int r,int no)
{
	if(node[no].l > r || node[no].r < l)
		return 0;
	if(node[no].l >= l && node[no].r <= r)
		return node[no].sum;
	if(node[no].tag != -1)
		down(no);
	return query2(l,r,no<<1) + query2(l,r,no<<1|1);
}
//void init(int n)
//{
//	for (int no = 1; no <= (n << 2); no ++ )
//	{
//		node[no].l = node[no].r = node[no].max = node[no].max2 = node[no].num = node[no].sum = node[no].tag = 0;
//	}
//}

int main()
{
	int T;
	scanf("%d",&T);
	while(T -- )
	{
		int n,m;
		scanf("%d%d",&n,&m);
//		init(n);
		for (int i = 1; i <= n; i ++ )
		{
			scanf("%d",&a[i]);
		}
		build(1,n,1);
		while(m -- )
		{
			int f ;
			scanf("%d",&f);
			if(f == 0)
			{
				int l,r,num;
				scanf("%d%d%d",&l,&r,&num);
				update(l,r,num,1);
			}
			else if(f == 1)
			{
				int l,r;
				scanf("%d%d",&l,&r);
				int ans = query1(l,r,1);
				printf("%d\n",ans);
			}
			else if(f == 2)
			{
				int l,r;
				scanf("%d%d",&l,&r);
				ll ans = query2(l,r,1);
				printf("%lld\n",ans);
			}
		}
	}
 } 

你可能感兴趣的:(学习笔记)