zoukankan      html  css  js  c++  java
  • SPOJ

    题目

    传送门

    解法

    考虑一次操作 ((0,x,y,k)) 对前缀和 (s_i) 的影响:

    [Delta =egin{cases} kcdot(i-x+1), & xle ile y \kcdot (y-x+1), & i>yend{cases} ]

    先给每个下标设定一个 (c_i) 表示增加的定值,(k_i) 表示增加的 (i) 的系数。

    那么询问 ((x,y)) 的答案就是:

    [ ext{Ans}=max_{i=x}^y{s_i+c_i+k_icdot i} ]

    显然是过不去的。不过事实上可以将区间分块。

    • (s_i) 还是表示 (i) 下标,处理非整块的情况。
    • (c_i,k_i) 都表示第 (i) 个块的值。

    问题转化为在长度为 (B) 的块内查找上文的 (max)

    将下标 (i) 抽象成点 ((i,s_i)),那么 ( ext{Ans}) 相当于斜率为 (-k_{bl_i}) 的过点 (i,iin S_{bl_i}) 的最大截距。维护一个上凸包,然后在凸包上二分斜率即可。当凸包被散块修改时,暴力重构凸包。

    接下来计算一下复杂度:

    • 修改。(mathcal O(mcdot (B+frac{n}{B})))
    • 查询。处理散块是 (mathcal O(mB)) 的;对于整块,暴力重构单次是 (mathcal O(B)) 的,总共是 (mathcal O(mB)) 的,二分是 (mathcal O(mcdot frac{n}{B}cdot logsqrt B)) 的。

    所以最优块长应该满足 (frac{B^2}{log sqrt B}=n)(但是我没算常数),可能比 (sqrt n) 略大,我直接取了 (sqrt n)

    代码

    #include <cstdio>
    #define print(x,y) write(x),putchar(y)
    
    template <class T>
    inline T read(const T sample) {
    	T x=0; char s; bool f=0;
    	while((s=getchar())>'9' or s<'0')
    		f|=(s=='-');
    	while(s>='0' and s<='9')
    		x=(x<<1)+(x<<3)+(s^48),
    		s=getchar();
    	return f?-x:x;
    }
    
    template <class T>
    inline void write(const T x) {
    	if(x<0) {
    		putchar('-'),write(-x);
    		return;
    	}
    	if(x>9) write(x/10);
    	putchar(x%10^48);
    } 
    
    #include <cmath>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    
    const int maxn=5e4+500,maxb=230;
    
    int n,m,B,bl[maxn],K,x,y;
    int st[maxb][maxb];
    ll s[maxn],k[maxn],c[maxn];
    
    void modify(int pos,int l=0,int r=0) {
    	if(l and r) {
    		st[pos][0]=0;
    		ll tmp=1ll*K*(l-x+1);
    		for(int i=l;i<=r;++i)
    			s[i]+=tmp,tmp+=K;
    	}
    	else k[pos]+=K,c[pos]+=1ll*K*(1-x);
    }
    
    ll query(int pos,int l=0,int r=0) {
    	if(l and r) {
    		ll tmp=s[l]+k[pos]*l;
    		for(int i=l+1;i<=r;++i)
    			tmp=max(tmp,s[i]+k[pos]*i);
    		return tmp+c[pos];
    	}
    	if(!st[pos][0]) {
    		int *tp=&st[pos][0];
    		for(int i=(pos-1)*B+1;i<=pos*B;++i) {
    			while((*tp)>1 and 1ll*(s[i]-s[st[pos][*tp]])*(st[pos][*tp]-st[pos][*tp-1])>1ll*(s[st[pos][*tp]]-s[st[pos][*tp-1]])*(i-st[pos][*tp]))
    				--(*tp);
    			st[pos][++(*tp)]=i;
    		}
    	}
    	l=1,r=st[pos][0]-1; int mid,a,b;
    	while(l<=r) {
    		mid=l+r>>1;
    		a=st[pos][mid];
    		b=st[pos][mid+1];
    		if(s[b]-s[a]>-k[pos]*(b-a))
    			l=mid+1;
    		else r=mid-1;
    	}
    	return s[st[pos][l]]+c[pos]+k[pos]*st[pos][l];
    }
    
    signed main() {
    	n=read(9); B=sqrt(n);
    	for(int i=1;i<=n;++i)	
    		s[i]=s[i-1]+read(9),
    		bl[i]=(i-1)/B+1;
    	m=read(9);
    	int op; ll ans;
    	while(m--) {
    		op=read(9),x=read(9);
    		y=read(9);
    		if(!op) {
    			K=read(9);
    			if(bl[x]^bl[y]) {
    				modify(bl[x],x,bl[x]*B);
    				modify(bl[y],(bl[y]-1)*B+1,y);
    				for(int i=bl[x]+1;i<bl[y];++i)	
    					modify(i);
    			}
    			else modify(bl[x],x,y);
    			K*=(y-x+1);
    			for(int i=y+1;i<=bl[y]*B;++i)
    				s[i]+=K;
    			for(int i=bl[y]+1;i<=bl[n];++i)
    				c[i]+=K;
    		}
    		else {
    			ans=0;
    			if(bl[x]^bl[y]) {
    				ans=query(bl[x],x,bl[x]*B);
    				ans=max(ans,query(bl[y],(bl[y]-1)*B+1,y));
    				for(int i=bl[x]+1;i<bl[y];++i)	
    					ans=max(ans,query(i));
    			}
    			else ans=query(bl[x],x,y);
    			print(ans,'
    ');
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    LeetCode236. 二叉树的最近公共祖先
    LeetCode235. 二叉搜索树的最近公共祖先
    LeetCode第32场双周赛
    .NET+Vue 使用SignalR推送数据
    Asp.Net Core使用MongoDB
    CentOS8 部署SqlServer
    windows 任何软件出现异常有日志 w3wp.exe [10608]中发生了未处理的Microsoft .Net Framework异常
    C# Socket使用以及DotNetty和Supersocket 框架
    C# 数据结构与算法 操作系统原理 计算机网络原理 数据库开发学习
    DotNet .Net Framework与Net Core与Net Standard 以及.NET5
  • 原文地址:https://www.cnblogs.com/AWhiteWall/p/12747997.html
Copyright © 2011-2022 走看看