zoukankan      html  css  js  c++  java
  • [UOJ 164] V

    一、题目

    点此看题

    二、解法

    宋队写矩阵直接 ( t T) 飞了,这么多操作好像势能线段树也很难(...)

    ( t observation):对于最难搞的二操作,新的值是关于原来值的只有一个折点的折线函数。

    那么我们尝试维护函数 (f(x)=max(x+a,b)),对于前三种操作,可以写出它们的函数:

    • 区间加操作:(f(x)={x_i,-inf})
    • 区间减操作:(f(x)={-x_i,0})
    • 区间赋值操作:(f(x)={-inf,x_i})

    然后我们 ( t DIY) 一下这个函数的运算法则就行了,首先考虑标记的合并:

    [max(max(x+a,b)+c,d)=max(x+a+c,max(b+c,d)) ]

    发现合并函数是和 (x) 无关的,所以这东西满足结合律,可以类似普通标记下传。

    然后考虑怎么维护区间历史最大值,我们考虑两个函数 (f_1(x)={a,b},f_2(x)={c,d}) 如何取最值:

    [max(max(x+a,b),max(x+c,d))=max(x+max(a,b),max(c,d)) ]

    所以再维护 (g(x)) 表示操作序列的历史最大值,用自己的 (f(x)) 和传下来的 (g'(x)) 合并再用上面的运算法则更新它即可,最后你发现这和加法的历史最大值做法其实差不多,时间复杂度 (O(nlog n))

    三、总结

    如果难搞的操作只有一个,可以思考它的特点再考虑怎么维护,本题就是以他为中心自己 ( t DIY) 了函数及其运算法则。

    #include <cstdio>
    #include <iostream>
    using namespace std;
    const int M = 500005;
    #define int long long
    const int inf = 1e15;
    int read()
    {
        int x=0,f=1;char c;
        while((c=getchar())<'0' || c>'9') {if(c=='-') f=-1;}
        while(c>='0' && c<='9') {x=(x<<3)+(x<<1)+(c^48);c=getchar();}
        return x*f;
    }
    int n,m,a[M];
    struct node
    {
    	int x,y;
    	node(int X=0,int Y=0)
    	{
    		x=X;y=Y;
    		if(x<-inf) x=-inf;
    		if(y<-inf) y=-inf;
    	}
    	void clear() {x=y=0;}
    	node operator + (const node &b) const
    	{
    		return node(max(x,b.x),max(y,b.y));
    	}
    	node operator * (const node &b) const
    	{
    		return node(x+b.x,max(y+b.x,b.y));
    	}
    }mx[4*M],hx[4*M];
    void fuck(int i,node a,node b)
    {
    	hx[i]=hx[i]+(mx[i]*b);
    	mx[i]=mx[i]*a;
    }
    void down(int i)
    {
    	fuck(i<<1,mx[i],hx[i]);
    	fuck(i<<1|1,mx[i],hx[i]);
    	mx[i].clear();hx[i].clear();
    }
    node con(int op,int c)
    {
    	if(op==1) return node(c,-inf);
    	if(op==2) return node(-c,0);
    	if(op==3) return node(-inf,c);
    	return node(0,0);
    }
    void upd(int i,int l,int r,int L,int R,node x)
    {
    	if(L>r || l>R) return ;
    	if(L<=l && r<=R)
    	{
    		fuck(i,x,x);
    		return ;
    	}
    	int mid=(l+r)>>1;down(i);
    	upd(i<<1,l,mid,L,R,x);
    	upd(i<<1|1,mid+1,r,L,R,x);
    }
    int ask(int i,int l,int r,int id)
    {
    	if(l==r) return max(mx[i].x+a[l],mx[i].y);
    	int mid=(l+r)>>1;down(i);
    	if(mid>=id) return ask(i<<1,l,mid,id);
    	return ask(i<<1|1,mid+1,r,id); 
    }
    int hask(int i,int l,int r,int id)
    {
    	if(l==r) return max(hx[i].x+a[l],hx[i].y);
    	int mid=(l+r)>>1;down(i);
    	if(mid>=id) return hask(i<<1,l,mid,id);
    	return hask(i<<1|1,mid+1,r,id); 
    }
    signed main()
    {
    	n=read();m=read();
    	for(int i=1;i<=n;i++)
    		a[i]=read();
    	while(m--)
    	{
    		int op=read();
    		if(op==4)
    			printf("%lld
    ",ask(1,1,n,read()));
    		else if(op==5)
    			printf("%lld
    ",hask(1,1,n,read()));
    		else
    		{
    			int l=read(),r=read(),c=read();
    			node t=con(op,c);
    			upd(1,1,n,l,r,t);
    		}
    	}
    }
    
  • 相关阅读:
    MYSQL进阶学习笔记十:MySQL慢查询!(视频序号:进阶_23-24)
    MYSQL进阶学习笔记九:MySQL事务的应用!(视频序号:进阶_21-22)
    MYSQL学习拓展一:MySQL 存储过程之游标的使用!
    MYSQL进阶学习笔记八:MySQL MyISAM的表锁!(视频序号:进阶_18-20)
    linux初级学习笔记十:linux grep及正则表达式!(视频序号:04_4)
    linux初级学习笔记九:linux I/O管理,重定向及管道!(视频序号:04_3)
    MYSQL进阶学习笔记七:MySQL触发器的创建,应用及管理!(视频序号:进阶_16,17)
    linux shell 字符串操作
    How to Install JAVA 8 (JDK/JRE 8u111) on Debian 8 & 7 via PPA
    iptables Data filtering详解
  • 原文地址:https://www.cnblogs.com/C202044zxy/p/15182495.html
Copyright © 2011-2022 走看看