codeforces 981E Addition on Segments

本文介绍了一种使用区间覆盖的方法解决特定类型的最大值问题。该问题要求找出在一系列区间增加操作后,数组中可能出现的最大值集合。通过构建线段树并进行懒标记优化,文章提供了一种高效算法实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

http://www.elijahqi.win/archives/3523
题目描述
Grisha come to a contest and faced the following problem.

You are given an array of size

n

n , initially consisting of zeros. The elements of the array are enumerated from

1

1 to

n

n . You perform

q

q operations on the array. The

i

i -th operation is described with three integers

l_i

li​ ,

r_i

ri​ and

x_i

xi​ (

1 \leq l_i \leq r_i \leq n

1≤li​≤ri​≤n ,

1 \leq x_i \leq n

1≤xi​≤n ) and means that you should add

x_i

xi​ to each of the elements with indices

l_i, l_i + 1, \ldots, r_i

li​,li​+1,…,ri​ . After all operations you should find the maximum in the array.

Grisha is clever, so he solved the problem quickly.

However something went wrong inside his head and now he thinks of the following question: “consider we applied some subset of the operations to the array. What are the possible values of the maximum in the array?”

Help Grisha, find all integers

y

y between

1

1 and

n

n such that if you apply some subset (possibly empty) of the operations, then the maximum in the array becomes equal to

y

y .

输入输出格式
输入格式:
The first line contains two integers

n

n and

q

q (

1 \leq n, q \leq 10^{4}

1≤n,q≤104 ) — the length of the array and the number of queries in the initial problem.

The following

q

q lines contain queries, one per line. The

i

i -th of these lines contains three integers

l_i

li​ ,

r_i

ri​ and

x_i

xi​ (

1 \leq l_i \leq r_i \leq n

1≤li​≤ri​≤n ,

1 \leq x_i \leq n

1≤xi​≤n ), denoting a query of adding

x_i

xi​ to the segment from

l_i

li​ -th to

r_i

ri​ -th elements of the array, inclusive.

输出格式:
In the first line print the only integer

k

k , denoting the number of integers from

1

1 to

n

n , inclusive, that can be equal to the maximum in the array after applying some subset (possibly empty) of the given operations.

In the next line print these

k

k integers from

1

1 to

n

n — the possible values of the maximum. Print these integers in increasing order.

输入输出样例
输入样例#1: 复制

4 3
1 3 1
2 4 2
3 4 4
输出样例#1: 复制

4
1 2 3 4
输入样例#2: 复制

7 2
1 5 1
3 7 2
输出样例#2: 复制

3
1 2 3
输入样例#3: 复制

10 3
1 1 2
1 1 3
1 1 6
输出样例#3: 复制

6
2 3 5 6 8 9
说明
Consider the first example. If you consider the subset only of the first query, the maximum is equal to

1

1 . If you take only the second query, the maximum equals to

2

2 . If you take the first two queries, the maximum becomes

3

3 . If you take only the fourth query, the maximum becomes

4

4 . If you take the fourth query and something more, the maximum becomes greater that

n

n , so you shouldn’t print it.

In the second example you can take the first query to obtain

1

1 . You can take only the second query to obtain

2

2 . You can take all queries to obtain

3

3 .

In the third example you can obtain the following maximums:

You can achieve the maximim of
2

2 by using queries:

(1)

(1) .

You can achieve the maximim of
3

3 by using queries:

(2)

(2) .

You can achieve the maximim of
5

5 by using queries:

(1, 2)

(1,2) .

You can achieve the maximim of
6

6 by using queries:

(3)

(3) .

You can achieve the maximim of
8

8 by using queries:

(1, 3)

(1,3) .

You can achieve the maximim of
9

9 by using queries:

(2, 3)

(2,3) .

stl大法好这题有个问题只要想明白了即可

那就是我其实只需要最后去看一下能否凑成即可 不需要考虑是否是最大 因为在选择的时候我们可以任选子集 可以尝试 好一个数通过好多次加法之后他不是最大的 那么一定构造不出

所以我们首先类似线段树区间覆盖 给每个加的数 懒标记覆盖

然后最后所有操作都做完了 从底向上以此合并即可 先合并 然后再把本层的懒标记搞定 这样是对的

#include<cstdio>
#include<bitset>
#include<vector>
#include<algorithm>
#define lc (x<<1)
#define rc (x<<1|1)
using namespace std;
inline char gc(){
    static char now[1<<16],*S,*T;
    if (T==S){T=(S=now)+fread(now,1,1<<16,stdin);if(T==S) return EOF;}
    return *S++;
}
inline int read(){
    int x=0,f=1;char ch=gc();
    while(!isdigit(ch)) {if (ch=='-') f=-1;ch=gc();}
    while(isdigit(ch)) x=x*10+ch-'0',ch=gc();
    return x*f;
}
const int N=1e4+10;
bitset<N> s[N<<2];
vector<int> a[N<<2];
int n,m;
inline void modify(int x,int l,int r,int l1,int r1,int v){
    if (l1<=l&&r1>=r) {a[x].push_back(v);return;}
    int mid=l+r>>1;
    if(l1<=mid) modify(lc,l,mid,l1,r1,v);
    if (r1>mid) modify(rc,mid+1,r,l1,r1,v);
}
inline void query(int x,int l,int r){
    if (l==r){s[x][0]=1;
        for (int i=0;i<a[x].size();++i) s[x]=s[x]<<a[x][i]|s[x];
        return; 
    }int mid=l+r>>1;
    query(lc,l,mid);query(rc,mid+1,r);
    s[x]=s[lc]|s[rc];
    for (int i=0;i<a[x].size();++i) s[x]=s[x]<<a[x][i]|s[x];
}
int main(){
//  freopen("e.in","r",stdin);
    n=read();m=read();
    for (int i=1;i<=m;++i){
        int l=read(),r=read(),x=read();
        modify(1,1,n,l,r,x);
    }query(1,1,n);int tot=0;
    for (int i=1;i<=n;++i) if (s[1][i]) ++tot;printf("%d\n",tot);
    for (int i=1;i<=n;++i) if (s[1][i]) printf("%d ",i);puts("");
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值