zoukankan      html  css  js  c++  java
  • 【bzoj4695】最假女选手 线段树区间最值操作

    题目描述

    给定一个长度为 N 序列,编号从 1 到 N 。要求支持下面几种操作:
    1.给一个区间[L,R] 加上一个数x 
    2.把一个区间[L,R] 里小于x 的数变成x 
    3.把一个区间[L,R] 里大于x 的数变成x 
    4.求区间[L,R] 的和
    5.求区间[L,R] 的最大值
    6.求区间[L,R] 的最小值

    输入

    第一行一个整数 N 表示序列长度。
    第二行 N 个整数 Ai 表示初始序列。
    第三行一个整数 M 表示操作个数。
    接下来 M 行,每行三或四个整数,第一个整数 Tp 表示操作类型,接下来 L,R,X 或 L,R 表述操作数。
    1<=tp<=6,N,M<=5*10^5,|Ai|<=10^8
    Tp=1时,|x|<=1000
    Tp=2或3时,|x|<=10^8

    输出

    对于每个4,5,6类型的操作输出一行一个整数表示答案。

    样例输入

    2
    1 2
    2
    2 1 2 2
    4 1 2

    样例输出

    4


    题解

    线段树区间最值操作

    吉老师的Segment tree Beats! 中的题。

    维护区间最小值、最小值个数、严格次小值、最大值、最大值个数、严格次大值、区间和、区间加和标记即可。。。

    还要注意,修改区间最小值时要注意其对最大值、严格次大值是否有影响,修改区间最大值时要注意其对最小值、严格次小值的影响。

    想想都觉得麻烦。。。

    时间复杂度 $O(nlog^2n)$ 

    注意本题略微卡常,不能全用long long,只有区间和使用long long维护。

    #include <cstdio>
    #include <algorithm>
    #define N 2000010
    #define lson l , mid , x << 1
    #define rson mid + 1 , r , x << 1 | 1
    using namespace std;
    typedef long long ll;
    const int inf = 1 << 30;
    int mx[N] , cx[N] , sx[N] , mn[N] , cn[N] , sn[N] , add[N];
    ll sum[N];
    inline void pushup(int x)
    {
    	int ls = x << 1 , rs = x << 1 | 1;
    	sum[x] = sum[ls] + sum[rs];
    	if(mx[ls] > mx[rs]) mx[x] = mx[ls] , cx[x] = cx[ls] , sx[x] = max(sx[ls] , mx[rs]);
    	if(mx[ls] < mx[rs]) mx[x] = mx[rs] , cx[x] = cx[rs] , sx[x] = max(mx[ls] , sx[rs]);
    	if(mx[ls] == mx[rs]) mx[x] = mx[ls] , cx[x] = cx[ls] + cx[rs] , sx[x] = max(sx[ls] , sx[rs]);
    	if(mn[ls] < mn[rs]) mn[x] = mn[ls] , cn[x] = cn[ls] , sn[x] = min(sn[ls] , mn[rs]);
    	if(mn[ls] > mn[rs]) mn[x] = mn[rs] , cn[x] = cn[rs] , sn[x] = min(mn[ls] , sn[rs]);
    	if(mn[ls] == mn[rs]) mn[x] = mn[ls] , cn[x] = cn[ls] + cn[rs] , sn[x] = min(sn[ls] , sn[rs]);
    }
    inline void pushdown(int l , int r , int x)
    {
    	int ls = x << 1 , rs = x << 1 | 1;
    	if(add[x])
    	{
    		int mid = (l + r) >> 1;
    		mx[ls] += add[x] , sx[ls] += add[x] , mn[ls] += add[x] , sn[ls] += add[x] , sum[ls] += (mid - l + 1) * add[x] , add[ls] += add[x];
    		mx[rs] += add[x] , sx[rs] += add[x] , mn[rs] += add[x] , sn[rs] += add[x] , sum[rs] += (r - mid) * add[x] , add[rs] += add[x];
    		add[x] = 0;
    	}
    	if(mx[ls] > mx[x]) 
    	{
    		if(mn[ls] == mx[ls]) mn[ls] = mx[x];
    		if(sn[ls] == mx[ls]) sn[ls] = mx[x];
    		sum[ls] += 1ll * (mx[x] - mx[ls]) * cx[ls] , mx[ls] = mx[x];
    	}
    	if(mx[rs] > mx[x])
    	{
    		if(mn[rs] == mx[rs]) mn[rs] = mx[x];
    		if(sn[rs] == mx[rs]) sn[rs] = mx[x];
    		sum[rs] += 1ll * (mx[x] - mx[rs]) * cx[rs] , mx[rs] = mx[x];
    	}
    	if(mn[ls] < mn[x])
    	{
    		if(mx[ls] == mn[ls]) mx[ls] = mn[x];
    		if(sx[ls] == mn[ls]) sx[ls] = mn[x];
    		sum[ls] += 1ll * (mn[x] - mn[ls]) * cn[ls] , mn[ls] = mn[x];
    	}
    	if(mn[rs] < mn[x])
    	{
    		if(mx[rs] == mn[rs]) mx[rs] = mn[x];
    		if(sx[rs] == mn[rs]) sx[rs] = mn[x];
    		sum[rs] += 1ll * (mn[x] - mn[rs]) * cn[rs] , mn[rs] = mn[x];
    	}
    }
    void build(int l , int r , int x)
    {
    	if(l == r)
    	{
    		scanf("%lld" , &sum[x]) , mx[x] = mn[x] = sum[x] , cx[x] = cn[x] = 1 , sx[x] = -inf , sn[x] = inf;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(lson) , build(rson);
    	pushup(x);
    }
    void vadd(int b , int e , int a , int l , int r , int x)
    {
    	if(b <= l && r <= e)
    	{
    		mx[x] += a , sx[x] += a , mn[x] += a , sn[x] += a , sum[x] += 1ll * (r - l + 1) * a , add[x] += a;
    		return;
    	}
    	pushdown(l , r , x);
    	int mid = (l + r) >> 1;
    	if(b <= mid) vadd(b , e , a , lson);
    	if(e > mid) vadd(b , e , a , rson);
    	pushup(x);
    }
    void vmax(int b , int e , int a , int l , int r , int x)
    {
    	if(mn[x] >= a) return;
    	if(b <= l && r <= e && sn[x] > a)
    	{
    		if(mx[x] == mn[x]) mx[x] = a;
    		if(sx[x] == mn[x]) sx[x] = a;
    		sum[x] += 1ll * (a - mn[x]) * cn[x] , mn[x] = a;
    		return;
    	}
    	pushdown(l , r , x);
    	int mid = (l + r) >> 1;
    	if(b <= mid) vmax(b , e , a , lson);
    	if(e > mid) vmax(b , e , a , rson);
    	pushup(x);
    }
    void vmin(int b , int e , int a , int l , int r , int x)
    {
    	if(mx[x] <= a) return;
    	if(b <= l && r <= e && sx[x] < a)
    	{
    		if(mn[x] == mx[x]) mn[x] = a;
    		if(sn[x] == mx[x]) sn[x] = a;
    		sum[x] += 1ll * (a - mx[x]) * cx[x] , mx[x] = a;
    		return;
    	}
    	pushdown(l , r , x);
    	int mid = (l + r) >> 1;
    	if(b <= mid) vmin(b , e , a , lson);
    	if(e > mid) vmin(b , e , a , rson);
    	pushup(x);
    }
    ll qsum(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e) return sum[x];
    	pushdown(l , r , x);
    	int mid = (l + r) >> 1; ll ans = 0;
    	if(b <= mid) ans += qsum(b , e , lson);
    	if(e > mid) ans += qsum(b , e , rson);
    	return ans;
    }
    int qmax(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e) return mx[x];
    	pushdown(l , r , x);
    	int mid = (l + r) >> 1 , ans = -inf;
    	if(b <= mid) ans = max(ans , qmax(b , e , lson));
    	if(e > mid) ans = max(ans , qmax(b , e , rson));
    	return ans;
    }
    int qmin(int b , int e , int l , int r , int x)
    {
    	if(b <= l && r <= e) return mn[x];
    	pushdown(l , r , x);
    	int mid = (l + r) >> 1 , ans = inf;
    	if(b <= mid) ans = min(ans , qmin(b , e , lson));
    	if(e > mid) ans = min(ans , qmin(b , e , rson));
    	return ans;
    }
    int main()
    {
    	int n , m , opt , x , y , z;
    	scanf("%d" , &n);
    	build(1 , n , 1);
    	scanf("%d" , &m);
    	while(m -- )
    	{
    		scanf("%d%d%d" , &opt , &x , &y);
    		if(opt == 1) scanf("%d" , &z) , vadd(x , y , z , 1 , n , 1);
    		if(opt == 2) scanf("%d" , &z) , vmax(x , y , z , 1 , n , 1);
    		if(opt == 3) scanf("%d" , &z) , vmin(x , y , z , 1 , n , 1);
    		if(opt == 4) printf("%lld
    " , qsum(x , y , 1 , n , 1));
    		if(opt == 5) printf("%d
    " , qmax(x , y , 1 , n , 1));
    		if(opt == 6) printf("%d
    " , qmin(x , y , 1 , n , 1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    在Web服务调试时,出现IIS配置错误的相应解决办法
    Eclipse解决Launch error: Failed to connect to remote VM [duplicate]
    在Eclipse中应该怎样去修改Android应用程序的包名(注意按步骤修改)
    用Fragment实现Tab页面切换效果初步总结
    与像素无关的dp单位与像素单位px之间的转换
    在Andorid开发项目中遇到的Bug记录(续)
    java邮件
    图片上传实例
    java多线程总结一:线程的两种创建方式及优劣比较
    java多线程总结二:后台线程(守护线程)
  • 原文地址:https://www.cnblogs.com/GXZlegend/p/8350181.html
Copyright © 2011-2022 走看看