CF981E Addition on Segments(线段树分治+bitset)

观察本题,我们发现,如果某些操作每次都更新到了某个位置,那么我们可以通过维护bitset来发现这个对于这个位置来说的可能最大值

而且答案就是所有位置取一下或。因为我们发现对于每个位置,bitset上为1的那些数一定可以取到最大值。

但是这样过于暴力,我们发现这是一个区间操作,而区间操作一般和线段树相结合,因此采用线段树分治,先对这段操作影响到的区间打标记

最后从根一直往下传递,就能把所有影响到每个位置的答案计算出来

初始化0这个位置是合法的

 #include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
typedef pair<int,pll> plll;
const int N=1e6+10;
const int inf=0x3f3f3f3f;
const int mod=1e9+7;
bitset<10010> ans;
bitset<10010> s;
struct node{
    int l,r;
    vector<int> num;
}tr[N];
void build(int u,int l,int r){
    if(l==r){
        tr[u]={l,r};
    }
    else{
        tr[u]={l,r};
        int mid=l+r>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
    }
}
void modify(int u,int l,int r,int k){
    if(tr[u].l>=l&&tr[u].r<=r){
        tr[u].num.push_back(k);
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    if(l<=mid)
        modify(u<<1,l,r,k);
    if(r>mid)
        modify(u<<1|1,l,r,k);
}
void dfs(bitset<10010> x,int u){
    auto cur=x;
    for(auto a:tr[u].num){
        cur|=(cur<<a);
    }
    if(tr[u].l==tr[u].r){
        ans|=cur;
        return ;
    }
    int mid=tr[u].l+tr[u].r>>1;
    dfs(cur,u<<1);
    dfs(cur,u<<1|1);
}
int main(){
    ios::sync_with_stdio(false);
    int n,q;
    cin>>n>>q;
    s[0]=1;
    build(1,1,n);
    while(q--){
        int l,r,k;
        cin>>l>>r>>k;
        modify(1,l,r,k);
    }
    dfs(s,1);
    int cnt=0;
    for(int i=1;i<=n;i++){
        if(ans[i])
            cnt++;
    }
    cout<<cnt<<endl;
    for(int i=1;i<=n;i++){
        if(ans[i])
            cout<<i<<" ";
    }
    cout<<endl;
    return 0;
}
View Code
没有人不辛苦,只有人不喊疼
原文地址:https://www.cnblogs.com/ctyakwf/p/13565344.html