uoj164. 【清华集训2015】V

Picks博士观察完金星凌日后,设计了一个复杂的电阻器。为了简化题目,题目中的常数与现实世界有所不同。

这个电阻器内有编号为  1n 1∼n 的  n n 个独立水箱,水箱呈圆柱形,底面积为  1 m2 1 m2,每个水箱在顶部和底部各有一个阀门,可以让水以  1 m3/s 1 m3/s 的流量通过,每个水箱的上阀门接水龙头,可以无限供应水,下阀门不接东西,可以让水流出。水箱顶部和底部都有一个接口,水的电阻率为  1 Ωm 1 Ω⋅m

水箱的高度足够高,有一个导电浮标浮在水面上,通过导线与水箱顶的接口相连。一开始时第  i i 个水箱中有  ai m3 ai m3 的水。

Picks博士接下来就需要对这个复杂的电阻器进行调试。他会进行以下五种操作。

1、打开编号在  [l,r] [l,r] 中的所有水箱的上方阀门  x x 秒,然后关上它们的上方阀门。

2、打开编号在  [l,r] [l,r] 中的所有水箱的下方阀门  x x 秒,然后关上它们的下方阀门。

3、将编号在  [l,r] [l,r] 中的所有水箱的下方阀门与大海通过连通器以一定方式相连,使得这些水箱中都恰拥有  x m3 x m3 的水,然后关上它们的下方阀门,撤去连通器。

4、在第  y y 个水箱的上下方接口处接上一个电动势为  1 V 1 V 的电源,电源没有内阻,Picks博士会测量出通过电源的电流大小,之后撤去该电源。

5、由于水浸泡过的地方会留下明显的水渍而没有被水浸泡过的地方不会有,Picks博士可以据此测量出此时第  y y 个水箱的水渍高度,以推断曾经最多有多少水,节约他的建造成本。

现在,他请你来帮他做预实验,你能告诉他每次测量得到的电流大小以及测量得到的最多的水量是多少吗?

输入格式

第一行两个数: n,m n,m

接下来一行  n n 个数,第  i i 个数表示初始时第  i i 个水箱内有  ai m3 ai m3 的水。

接下来  m m 行中,第  i i 行第一个数  ti ti 表示操作类型:

若  ti=1 ti=1,则接下来三个整数  li,ri,xi li,ri,xi,表示打开编号在  [li,ri] [li,ri] 中的所有水箱的上方接口  xi xi 秒。

若  ti=2 ti=2,则接下来三个整数  li,ri,xi li,ri,xi,表示打开编号在  [li,ri] [li,ri] 中的所有水箱的下方接口  xi xi 秒。

若  ti=3 ti=3,则接下来三个整数  li,ri,xi li,ri,xi,表示将编号在  [li,ri] [li,ri] 中的所有水箱与大海连接,使这些水箱中都恰有  xi m3 xi m3 的水。

若  ti=4 ti=4,则接下来一个整数  yi yi,表示测量在第  yi yi 个水箱的上下方接口处接上一个电动势为  1 V 1 V 的电源时通过电源的电流。

若  ti=5 ti=5,则接下来一个整数  yi yi,表示测量此时在第  yi yi 个水箱中的水渍高度。

输出格式

对于每个  ti=4 ti=4,输出一个整数表示通过电源的电流大小的倒数(单位为  A1 A−1 ),如果电流为无穷大则输出0。

对于每个  ti=5 ti=5,输出一个整数表示在第  yi yi 个水箱中的水渍高度(单位为  m m )。

样例输入一

5 6
1 2 3 4 5
2 1 3 2
4 1
1 1 4 1
5 3
3 1 5 4
4 2

样例输出一

0
3
4

样例输入二

见相关文件下载

样例输出二

见相关文件下载

样例输入三

见相关文件下载

样例输出三

见相关文件下载

限制与约定

时间限制: 2s 2s

空间限制: 128MB 128MB

测试点编号 n= n= m= m= 约定
1 1000 1000 1000 1000  
2 1000 1000 1000 1000  
3 105 105 105 105 没有操作2
4 5×105 5×105 5×105 5×105 没有操作2
5 105 105 105 105 没有操作1与操作5
6 105 105 105 105 没有操作1
7 5×105 5×105 5×105 5×105 没有操作1
8 5×105 5×105 5×105 5×105 没有操作5
9 105 105 105 105  
10 5×105 5×105 5×105 5×105  

对于所有的数据: 1n,m5×105, 0ai,xi109,1lirin, 1yin 1≤n,m≤5×105, 0≤ai,xi≤109,1≤li≤ri≤n, 1≤yi≤n.

提示

可能用到的物理公式:

1、欧姆定律: I=UR I=UR,其中  I,U,R I,U,R 分别代表电流、电压和电阻。

2、电阻率公式: R=ρLS R=ρLS,其中  R,ρ,L,S

R,ρ,L,S 分别代表电阻、电阻率、电阻长度、横截面积。


简明题意:

维护一列数,,支持:

1.区间加A

2.区间减A,减法结束后每个位置与0取max

3.区间覆盖成A

4.询问单点当前值

5.询问单点历史最值


solution:

使用线段树维护,,定义标记(a,b),代表对于该点维护的区间,执行这个标记,对于区间内的数,都要先加上a然后与b取max,那么操作1 2 3分别对应标记(A,-INF) (-A,0) (-INF,A)

显然这个标记是可以下传的,,即(a + A,max(b + A,B))

对于询问5,可以维护区间最值标记,即区间加法达到过的最值,区间取max达到过的最值

这样,不论什么询问,标记下传完就得到答案了,O(nlogn)

#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;

const int maxn = 5E5 + 50;
const int T = 4;
typedef long long LL;
const LL INF = 1E15;

int n,m;
LL A[maxn*T],B[maxn*T],a[maxn*T],pa[maxn*T],b[maxn*T],pb[maxn*T];

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;
}

void Clear(int o)
{
	a[o] = pa[o] = 0; 
	b[o] = pb[o] = -INF;
}

void maintain(int o)
{
	int lc = (o<<1),rc = (o<<1|1);
	A[o] = max(A[lc],A[rc]);
	B[o] = max(B[lc],B[rc]);
}

void pushdown(int o,int l,int r)
{
	if (a[o] == 0 && b[o] == -INF) return;
	B[o] = max(B[o],max(A[o] + pa[o],pb[o]));
	if (l == r)
	{
		A[o] = max(A[o] + a[o],b[o]);
		Clear(o); return;
	}
	int lc = (o<<1),rc = (o<<1|1);
	pa[lc] = max(pa[lc],a[lc] + pa[o]); 
	pb[lc] = max(pb[lc],max(b[lc] + pa[o],pb[o]));
	pa[rc] = max(pa[rc],a[rc] + pa[o]);
	pb[rc] = max(pb[rc],max(b[rc] + pa[o],pb[o]));
	a[lc] += a[o]; b[lc] = max(b[lc] + a[o],b[o]);
	a[rc] += a[o]; b[rc] = max(b[rc] + a[o],b[o]);
	a[lc] = max(a[lc],-INF); a[rc] = max(a[rc],-INF);
	A[o] = max(A[o] + a[o],b[o]);
	Clear(o);
}

void Build(int o,int l,int r)
{
	if (l == r)
	{
		A[o] = B[o] = getint(); 
		Clear(o); return;
	}
	int mid = (l + r) >> 1; Clear(o);
	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,LL p,LL q)
{
	pushdown(o,l,r);
	if (ml <= l && r <= mr)
	{
		a[o] = pa[o] = p; 
		b[o] = pb[o] = q;
		pushdown(o,l,r); return;
	}
	int mid = (l + r) >> 1;
	if (ml <= mid) Modify(o<<1,l,mid,ml,mr,p,q); else pushdown(o<<1,l,mid);
	if (mr > mid) Modify(o<<1|1,mid+1,r,ml,mr,p,q); else pushdown(o<<1|1,mid+1,r);
	maintain(o);
}

LL Query(int o,int l,int r,int pos,int typ)
{
	pushdown(o,l,r);
	if (l == r) return typ == 4 ? A[o] : B[o];
	int mid = (l + r) >> 1;
	if (pos <= mid) return Query(o<<1,l,mid,pos,typ);
	else return Query(o<<1|1,mid+1,r,pos,typ);
}

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()
{
	
	n = getint(); m = getint(); Build(1,1,n);
	while (m--)
	{
		int typ = getint(),l,r,x;
		if (typ <= 3)
		{
			l = getint(); r = getint(); x = getint();
			if (typ == 1) Modify(1,1,n,l,r,x,0);
			else if (typ == 2) Modify(1,1,n,l,r,-x,0);
			else Modify(1,1,n,l,r,-INF,x);
		}
		else
		{
			int y = getint();
			Print(Query(1,1,n,y,typ));
		}
	}
	return 0;
}

你可能感兴趣的:(线段树)