HDU 5306 Gorgeous Sequence(线段树)

Description:

There is a sequence a a a of length n n n. We use a i a_i ai to denote the i i i-th element in this sequence. You should do the following three types of operations to this sequence.

0 <mtext>   </mtext> x <mtext>   </mtext> y <mtext>   </mtext> t 0\ x\ y\ t 0 x y t: For every x i y x \le i \le y xiy, we use m i n ( a i , t ) min(a_i, t) min(ai,t) to replace the original a i a_i ai's value.

1 <mtext>   </mtext> x <mtext>   </mtext> y 1\ x\ y 1 x y: Print the maximum value of a i a_i ai that x i y x \le i \le y xiy.

2 <mtext>   </mtext> x <mtext>   </mtext> y 2\ x\ y 2 x y: Print the sum of a i a_i ai that x i y x \le i \le y xiy.

Input:

The first line of the input is a single integer T T T, indicating the number of testcases.

The first line contains two integers n n n and m m m denoting the length of the sequence and the number of operations.

The second line contains n n n separated integers a 1 , , a n a_1, \ldots, a_n a1,,an ( 1 i n , 0 a i &lt; 2 31 \forall 1 \le i \le n, 0 \le a_i \lt 2^{31} 1in,0ai<231).

Each of the following m m m lines represents one operation ( 1 x y n , 0 t &lt; 2 31 1 \le x \le y \le n, 0\le t \lt 2^{31} 1xyn,0t<231).

It is guaranteed that T = 100 T=100 T=100, n 1000000 , <mtext>   </mtext> m 1000000 \sum n \le 1000000, \ \sum m \le 1000000 n1000000, m1000000.

Output:

For every operation of type 1 1 1 or 2 2 2, print one line containing the answer to the corresponding query.

Sample Input:

1
5 5
1 2 3 4 5
1 1 5
2 1 5
0 3 5 3
1 1 5
2 1 5

Sample Output:

5
15
3
12

Hint:

Please use efficient IO method

题目链接

n n n 个元素的序列 a r r arr arr 支持 m m m 次以下三种操作

  • 0 x y t 对区间 i [ x , y ] i\in[x,y] i[x,y] 的元素取 min ( a r r i , t ) \min(arr_{i}, t) min(arri,t)
  • 1 x y 求区间 i [ x , y ] i\in[x,y] i[x,y] 的最大值 max ( a r r i ) \max(arr_{i}) max(arri)
  • 2 x y i = x y a r r i \sum\limits_{i=x}^{y}arr_{i} i=xyarri

jls2016年信息学奥林匹克中国国家队候选队员论文中的一道例题,被无情的卡常了……结构体和 S T L STL STL 都被卡掉了……真毒瘤

因为在一节点打上区间取 min \min min 标记的时候无法快速更新区间和,所以不能通过传统的 l a z y lazy lazy 惰性标记解决

考虑另一种做法,线段树中每个节点维护区间最大值 m a ma ma 、区间严格次大值 s e se se 、区间最大值数量 t t t 、区间和 s u m sum sum

当我们进行区间更新对 x x x min \min min 时会遇到三种情况

  • m a x ma\le x max ,这种情况下显然 x x x 对区间无影响,退出
  • s e &lt; x &lt; m a se &lt; x &lt; ma se<x<ma ,这种情况下显然区间更新时指挥影响到 t t t 个最大值,所以 s u m + = t × ( x m a ) sum += t\times(x-ma) sum+=t×(xma) 并把 m a ma ma 更新为 x x x 即可
  • s e x se\ge x sex ,这种情况下无法至今进行更新,所以递归向小区间更新直到遇到前两种情况

AC代码:

#include <bits/stdc++.h>
using namespace std;
const int maxn = 1e6 + 5;

template <class T>
inline bool Read(T &ans) {
    char c;
    int sgn;
    if (c = getchar(), c == EOF) {
        return false;
    }
    while (c != '-' && (c < '0' || c > '9')) {
        c = getchar();
    }
    sgn = (c == '-') ? -1 : 1;
    ans = (c == '-') ? 0 : (c - '0');
    while (c = getchar(), c >= '0' && c <= '9') {
        ans = ans * 10 + (c - '0');
    }
    ans *= sgn;
    return true;
}

class seg_tree{
  public:
    int ma[maxn << 2], t[maxn << 2], se[maxn << 2];
    long long sum[maxn << 2];

    void Pull(int o) {
      sum[o] = sum[o << 1] + sum[o << 1 | 1];
      ma[o] = max(ma[o << 1], ma[o << 1 | 1]);
      se[o] = max(se[o << 1], se[o << 1 | 1]);
      t[o] = 0;
      if (ma[o << 1] != ma[o << 1 | 1]) se[o] = max(se[o], min(ma[o << 1], ma[o << 1 | 1]));
      if (ma[o] == ma[o << 1]) t[o] += t[o << 1];
      if (ma[o] == ma[o << 1 | 1]) t[o] += t[o << 1 | 1];
    }

    void Push(int o, int l, int r) {
      int m = (l + r) >> 1;
      if (ma[o] < ma[o << 1]) {
        sum[o << 1] += 1ll * (ma[o] - ma[o << 1]) * t[o << 1];
        ma[o << 1] = ma[o];
      }
      if (ma[o] < ma[o << 1 | 1]) {
        sum[o << 1 | 1] += 1ll * (ma[o] - ma[o << 1 | 1]) * t[o << 1 | 1];
        ma[o << 1 | 1] = ma[o];
      }
    }

    void Build(int o, int l, int r) {
      if (l == r) {
        Read(sum[o]);
        ma[o] = sum[o];
        t[o] = 1; se[o] = -1;
        return;
      }
      int m = (l + r) >> 1;
      Build(o << 1, l, m);
      Build(o << 1 | 1, m + 1, r);
      Pull(o);
    }

    void Modify(int o, int l, int r, int ll, int rr, int v) {
      if (ll <= l && rr >= r && v > se[o]) {
        if (v < ma[o]) {
          sum[o] += 1ll * (v - ma[o]) * t[o];
          ma[o] = v;
        }
        return;
      }
      Push(o, l, r);
      int m = (l + r) >> 1;
      if (ll <= m) Modify(o << 1, l, m, ll, rr, v);
      if (rr > m) Modify(o << 1 | 1, m + 1, r, ll, rr, v);
      Pull(o);
    }

    int QueryMax(int o, int l, int r, int ll, int rr) {
      if (ll <= l && rr >= r) return ma[o];
      Push(o, l, r);
      int m = (l + r) >> 1, ans = 0;
      if (ll <= m) ans = max(ans, QueryMax(o << 1, l, m, ll, rr));
      if (rr > m) ans = max(ans, QueryMax(o << 1 | 1, m + 1, r, ll, rr));
      return ans;
    }

    long long QuerySum(int o, int l, int r, int ll, int rr) {
      if (ll <= l && rr >= r) return sum[o];
      Push(o, l, r);
      int m = (l + r) >> 1;
      long long ans = 0;
      if (ll <= m) ans += QuerySum(o << 1, l, m, ll, rr);
      if (rr > m) ans += QuerySum(o << 1 | 1, m + 1, r, ll, rr);
      return ans;
    }
};

seg_tree sgt;

int main() {
  int t; Read(t);
  for (int cas = 1; cas <= t; ++cas) {
    int n, m; Read(n); Read(m);
    sgt.Build(1, 1, n);
    for (int i = 0, op, l, r, v; i < m; ++i) {
      Read(op); Read(l); Read(r);
      if (op == 0) {
        Read(v);
        sgt.Modify(1, 1, n, l, r, v);
      }
      else if (op == 1) printf("%d\n", sgt.QueryMax(1, 1, n, l, r));
      else printf("%lld\n", sgt.QuerySum(1, 1, n, l, r));
    }
  }
  return 0;
}
全部评论

相关推荐

ProMonkey2024:5个oc?厉害! 但是有一个小问题:谁问你了?😡我的意思是,谁在意?我告诉你,根本没人问你,在我们之中0人问了你,我把所有问你的人都请来 party 了,到场人数是0个人,誰问你了?WHO ASKED?谁问汝矣?誰があなたに聞きましたか?누가 물어봤어?我爬上了珠穆朗玛峰也没找到谁问你了,我刚刚潜入了世界上最大的射电望远镜也没开到那个问你的人的盒,在找到谁问你之前我连癌症的解药都发明了出来,我开了最大距离渲染也没找到谁问你了我活在这个被辐射蹂躏了多年的破碎世界的坟墓里目睹全球核战争把人类文明毁灭也没见到谁问你了(别的帖子偷来的,现学现卖😋)
点赞 评论 收藏
分享
点赞 收藏 评论
分享
牛客网
牛客企业服务