CF #535 (Div. 3) E2 Array and Segments (Hard version) 利用线段树进行区间转移

传送门

题意:

      有m个区间,n个a[ i ] , 选择若干个区间,使得整个数组中的最大值和最小值的差值最小。n<=1e5,m<=300;

思路:

    可以知道每个i,如果一个区间包含这个点,就让这个区间发挥作用。枚举每个i,找到最大值即可。

    当然这个复杂度不对,我们可以通过线段树保存数组的最大值和最小值,每次区间在左端点发挥作用,在右端点去掉作用。

#include <algorithm>
#include  <iterator>
#include  <iostream>
#include   <cstring>
#include   <cstdlib>
#include   <iomanip>
#include    <bitset>
#include    <cctype>
#include    <cstdio>
#include    <string>
#include    <vector>
#include     <stack>
#include     <cmath>
#include     <queue>
#include      <list>
#include       <map>
#include       <set>
#include   <cassert>

using namespace std;
#define lson (l , mid , rt << 1)
#define rson (mid + 1 , r , rt << 1 | 1)
#define debug(x) cerr << #x << " = " << x << "\n";
#define pb push_back
#define pq priority_queue

typedef long long ll;
typedef unsigned long long ull;
//typedef __int128 bll;
typedef pair<ll ,ll > pll;
typedef pair<int ,int > pii;
typedef pair<int,pii> p3;
typedef pair<ll,int>pli;
//priority_queue<int> q;//这是一个大根堆q
//priority_queue<int,vector<int>,greater<int> >q;//这是一个小根堆q
#define fi first
#define se second
//#define endl ‘\n‘
//#define R register
#define OKC ios::sync_with_stdio(false);cin.tie(0)
#define FT(A,B,C) for(int A=B;A <= C;++A)  //用来压行
#define REP(i , j , k)  for(int i = j ; i <  k ; ++i)
#define max3(a,b,c) max(max(a,b), c);
#define min3(a,b,c) min(min(a,b), c);
//priority_queue<int ,vector<int>, greater<int> >que;

const ll mos = 0x7FFFFFFF;  //2147483647
const ll nmos = 0x80000000;  //-2147483648
const int inf = 0x3f3f3f3f;
const ll inff = 0x3f3f3f3f3f3f3f3f; //18
//const int mod = 1e9+7;
const double esp = 1e-8;
const double PI=acos(-1.0);
const double PHI=0.61803399;    //黄金分割点
const double tPHI=0.38196601;

template<typename T>
inline T read(T&x){
    x=0;int f=0;char ch=getchar();
    while (ch<‘0‘||ch>‘9‘) f|=(ch==‘-‘),ch=getchar();
    while (ch>=‘0‘&&ch<=‘9‘) x=x*10+ch-‘0‘,ch=getchar();
    return x=f?-x:x;
}

/*-----------------------showtime---------------------*/

            const int maxn = 1e5+9;
            int mx[maxn<<2],mn[maxn<<2],dif[maxn<<2];
            int lazy[maxn<<2];

            int a[maxn];
            pii e[maxn];
            void pushup(int rt){
                mx[rt] = max(mx[rt<<1], mx[rt<<1|1]);
                mn[rt] = min(mn[rt<<1], mn[rt<<1|1]);
                dif[rt] = mx[rt] - mn[rt];
            }
            void build(int l,int r,int rt){
                if(l == r){
                    mx[rt] = mn[rt] = a[l];
                    dif[rt] = mx[rt] - mn[rt];
                    return;
                }

                int mid = (l + r) >> 1;
                build(l, mid, rt<<1);
                build(mid+1, r, rt<<1|1);
                pushup(rt);
            }
            vector<int>tmp,res;
            void pushdown(int rt){
                if(lazy[rt] == 0) return;
                lazy[rt<<1] += lazy[rt];
                lazy[rt<<1|1] += lazy[rt];
                mn[rt<<1] += lazy[rt];
                mn[rt<<1|1] += lazy[rt];
                mx[rt<<1] += lazy[rt];
                mx[rt<<1|1] += lazy[rt];
                lazy[rt] = 0;
                return;
            }
            void update(int L, int R ,int c,int l,int r,int rt){
                if(l>=L && r<=R){
                    mx[rt] += c;
                    mn[rt] += c;
                    lazy[rt] += c;
                    return;
                }
                pushdown(rt);
                int mid = (l + r) >> 1;
                if(mid >= L)update(L,R,c,l,mid,rt<<1);
                if(mid < R)update(L,R,c,mid+1,r,rt<<1|1);
                pushup(rt);
            }

int main(){
            int n,m;
            scanf("%d%d", &n, &m);
            for(int i=1; i<=n; i++) scanf("%d", &a[i]);
            build(1,n,1);

            for(int i=1; i<=m; i++) scanf("%d%d", &e[i].fi, &e[i].se);

            int ans = 0;

            for(int i=1; i<=n; i++){

                tmp.clear();

                for(int j=1; j<=m; j++){
                    if(e[j].fi == i){
                        update(e[j].fi,e[j].se,-1,1,n,1);
                    }
                    else if(e[j].se == i-1){
                        update(e[j].fi,e[j].se,1,1,n,1);
                    }
                    if(e[j].fi <=i && e[j].se >= i)
                        tmp.pb(j);
                }
                int q = dif[1];
                if(ans < q){
                    ans = q;
                  //  res.clear();
                    res = tmp;

                }

            }

            printf("%d\n", ans);
            printf("%d\n", (int)res.size());

            for(int i=0; i<(int)res.size(); i++){
                printf("%d ", res[i]);
            }
            puts("");
            return 0;
}

原文地址:https://www.cnblogs.com/ckxkexing/p/10316834.html

时间: 2024-08-30 15:03:22

CF #535 (Div. 3) E2 Array and Segments (Hard version) 利用线段树进行区间转移的相关文章

Codeforces 1108E2 Array and Segments (Hard version) 差分, 暴力

Codeforces 1108E2 E2. Array and Segments (Hard version) Description: The only difference between easy and hard versions is a number of elements in the array. You are given an array \(a\) consisting of \(n\) integers. The value of the \(i\)-th element

LightOJ Array Queries 1082【线段树求区间最值】

1082 - Array Queries PDF (English) Statistics Forum Time Limit: 3 second(s) Memory Limit: 64 MB Given an array with N elements, indexed from 1 to N. Now you will be given some queries in the form I J, your task is to find the minimum value from index

poj 1436 Horizontally Visible Segments(线段树、区间覆盖)

Horizontally Visible Segments Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4645   Accepted: 1706 Description There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

POJ 1436 Horizontally Visible Segments (线段树&amp;#183;区间染色)

题意   在坐标系中有n条平行于y轴的线段  当一条线段与还有一条线段之间能够连一条平行与x轴的线不与其他线段相交  就视为它们是可见的  问有多少组三条线段两两相互可见 先把全部线段存下来  并按x坐标排序  线段树记录相应区间从右往左当前可见的线段编号(1...n)  超过一条就为0  然后从左往右对每条线段  先查询左边哪些线段和它是可见的  把可见关系存到数组中  然后把这条线段相应区间的最右端可见编号更新为这条线段的编号  最后暴力统计有多少组即可了 #include <cstdio>

CF1108E1 Array and Segments (Easy version)(待更新)

题目地址:CF1108E1 加强版题解:https://www.cnblogs.com/xht37/p/10322344.html 原文地址:https://www.cnblogs.com/xht37/p/10322340.html

POJ 1436——Horizontally Visible Segments(线段树,区间染色+暴力)

Horizontally Visible Segments Time Limit: 5000MS   Memory Limit: 65536K Total Submissions: 4130   Accepted: 1511 Description There is a number of disjoint vertical line segments in the plane. We say that two segments are horizontally visible if they

ACdream1157 Segments(CDQ分治 + 线段树)

题目这么说的: 进行如下3种类型操作:1)D L R(1 <= L <= R <= 1000000000) 增加一条线段[L,R]2)C i (1-base) 删除第i条增加的线段,保证每条插入线段最多插入一次,且这次删除操作一定合法3) Q L R(1 <= L <= R <= 1000000000) 查询目前存在的线段中有多少条线段完全包含[L,R]这个线段,线段X被线段Y完全包含即LY <= LX <= RX <= RY) 初学CDQ分治是看了B

Codeforces Round #200 (Div. 1) D. Water Tree(dfs序加线段树)

思路: dfs序其实是很水的东西.  和树链剖分一样, 都是对树链的hash. 该题做法是:每次对子树全部赋值为1,对一个点赋值为0,查询子树最小值. 该题需要注意的是:当我们对一棵子树全都赋值为1的时候, 我们要查询一下赋值前子树最小值是不是0, 如果是的话, 要让该子树父节点变成0, 否则变0的信息会丢失. 细节参见代码: #include <cstdio> #include <cstring> #include <algorithm> #include <i