这个是干啥的?
其实就是个线段树,我也不知道为什么叫吉老师线段树
简单例题: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);
}
}
}
}