hdu5306 Gorgeous Sequence

题意:

给出一个数组A,要求维护三个操作:

1.给出l,r,t,对于l <= i <= r,Ai = min(Ai,t)

2.给出l,r,询问max{Ai} (l <= i <= r)

3.给出l,r,询问∑Ai (l <= i <= r)


solution:

考虑使用线段树,每个节点维护所在区间内的最大值fr,严格次大值sc,最大值出现次数ti,区间和sum

对区间取min操作,先在线段树上定位区间,分三类讨论:

1.fr <= t,此时修改对该区间毫无影响,,直接返回

2.sc < t < fr,此时仅最大值受影响,稍作修改,打上标记后返回

3.t <= sc,暴力递归左右子树


3操作这样暴力不会TLE???证明详见吉如一的论文,,实际上总复杂度为O(mlogn),但有常数代价

第一次写的时候sc没有及时清0,,导致多组测试的时候被卡爆了。。

实际上及时清零了也是2995ms。。。GG= =

#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cmath>
#include<cstring>
#include<vector>
#include<queue>
#include<set>
#include<map>
#include<stack>
#include<bitset>
#include<ext/pb_ds/priority_queue.hpp>
using namespace std;

const int maxn = 1E6 + 10;
const int T = 4;
typedef long long LL;
const int INF = ~0U>>1;

int n,m,ti[maxn*T],fr[maxn*T],sc[maxn*T],Min[maxn*T],A[maxn];
LL sum[maxn*T];

void maintain(int o)
{
	int lc = (o<<1),rc = (o<<1|1);
	if (fr[lc] == fr[rc])
	{
		ti[o] = ti[lc] + ti[rc];
		fr[o] = fr[lc]; sc[o] = max(sc[lc],sc[rc]);
	}
	else if (fr[lc] < fr[rc])
	{
		ti[o] = ti[rc]; fr[o] = fr[rc];
		sc[o] = max(sc[rc],fr[lc]);
	}
	else
	{
		ti[o] = ti[lc]; fr[o] = fr[lc];
		sc[o] = max(sc[lc],fr[rc]);
	}
	sum[o] = sum[lc] + sum[rc];
}

void pushdown(int o,int l,int r)
{
	if (Min[o] >= fr[o]) {Min[o] = INF; return;}
	int lc = (o<<1),rc = (o<<1|1);
	if (sc[o] < Min[o])
	{
		sum[o] += 1LL*ti[o]*(Min[o] - fr[o]);
		fr[o] = Min[o];
		if (l == r) {Min[o] = INF; return;}
		Min[lc] = min(Min[lc],Min[o]);
		Min[rc] = min(Min[rc],Min[o]);
		Min[o] = INF;
	}
	else
	{
		Min[lc] = min(Min[lc],Min[o]);
		Min[rc] = min(Min[rc],Min[o]);
		Min[o] = INF; int mid = (l + r) >> 1;
		pushdown(o<<1,l,mid);
		pushdown(o<<1|1,mid+1,r);
		maintain(o);
	}
}

void Build(int o,int l,int r)
{
	if (l == r)
	{
		sum[o] = fr[o] = A[l]; sc[o] = 0;
		ti[o] = 1; Min[o] = INF; return;
	}
	int mid = (l + r) >> 1; Min[o] = INF;
	Build(o<<1,l,mid); Build(o<<1|1,mid+1,r);
	maintain(o);
}

void Modify(int o,int l,int r,int ml,int mr,int k)
{
	if (ml <= l && r <= mr)
	{
		Min[o] = min(Min[o],k);
		pushdown(o,l,r); return;
	}
	int mid = (l + r) >> 1; pushdown(o,l,r);
	if (ml <= mid) Modify(o<<1,l,mid,ml,mr,k); else pushdown(o<<1,l,mid);
	if (mr > mid) Modify(o<<1|1,mid+1,r,ml,mr,k); else pushdown(o<<1|1,mid+1,r);
	maintain(o);
}

int Get_Max(int o,int l,int r,int ql,int qr)
{
	pushdown(o,l,r);
	if (ql <= l && r <= qr) return fr[o];
	int mid = (l + r) >> 1,ret = 0;
	if (ql <= mid) ret = Get_Max(o<<1,l,mid,ql,qr);
	if (qr > mid) ret = max(ret,Get_Max(o<<1|1,mid+1,r,ql,qr));
	return ret;
}

LL Get_Sum(int o,int l,int r,int ql,int qr)
{
	pushdown(o,l,r);
	if (ql <= l && r <= qr) return sum[o];
	int mid = (l + r) >> 1; LL ret = 0;
	if (ql <= mid) ret = Get_Sum(o<<1,l,mid,ql,qr);
	if (qr > mid) ret += Get_Sum(o<<1|1,mid+1,r,ql,qr);
	return ret;
}

int getint()
{
	char ch = getchar(); int ret = 0;
	while (ch < '0' || '9' < ch) ch = getchar();
	while ('0' <= ch && ch <= '9')
		ret = ret*10 + ch - '0',ch = getchar();
	return ret;
}

char ch[20];
void Print(LL x)
{
	if (!x) {puts("0"); return;}
	int len = 0;
	while (x) ch[++len] = x % 10LL,x /= 10LL;
	for (int i = len; i; i--) putchar(ch[i] + '0');
	puts("");
}

int main()
{
	#ifdef DMC
		freopen("DMC.txt","r",stdin);
		freopen("test.txt","w",stdout);
	#endif
	
	int cas = getint();
	while (cas--)
	{
		n = getint(); m = getint();
		for (int i = 1; i <= n; i++) A[i] = getint();
		Build(1,1,n);
		while (m--)
		{
			int typ = getint(),l,r;
			l = getint(); r = getint();
			if (!typ) Modify(1,1,n,l,r,getint());
			else if (typ == 1) Print(Get_Max(1,1,n,l,r));
			else Print(Get_Sum(1,1,n,l,r));
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值