D. Divide and Summarize

 题意:给你n个数,q次询问,问你能否具有满足和为s的序列,再求其有多少种和时需要使用m i d = m a x + m i n > > 1 来寻找有多少种和。

思路:手动模拟一下有点像线段树建树的过程,那就按照线段树来写,把线段树建树的过程改动一下,求出所有可能的序列的和,然后标记

,询问的时候看看存不存就可以了。(注意要开10倍空间!!!!!)

#include<bits/stdc++.h>
using namespace std;
const int N=2e5+10;
typedef long long ll;
ll a[N],b[N];
map<ll,ll>p,f;
int le;
struct node{
    ll sum;
} tree[N*10];
void pushup(int n)
{
    tree[n].sum=tree[n<<1].sum+tree[n<<1|1].sum;
    f[tree[n].sum]=1;
}
void build_tree(int n, ll l,ll r)
{
    if(l==r){
        tree[n].sum=b[l]*p[b[l]];
        f[tree[n].sum]=1;
    }
    else{
        ll mid=(b[l]+b[r])/2;
        ll pos=upper_bound(b,b+le,mid)-b;
        ll left_node= 2*n;
        ll right_node=2*n+1;
        build_tree(left_node,l,pos-1);
        build_tree(right_node,pos,r);
        pushup(n);
    }
}
int main(){
    int t;
    cin>>t;
    while(t--){
        int n,q;
        le=0;
        p.clear();
        f.clear();
        cin>>n>>q;
        for(int i=0;i<n+10;i++)
            b[i]=a[i]=0;
         for(int i=0;i<(n<<2)+10;i++)
             tree[i].sum=0;
        for(int i=0; i<n; i++){
            cin>>a[i];
            if(p[a[i]]==0){
                b[le]=a[i];
                le++;
            }
            p[a[i]]++;
        }
        sort(b,b+le);
        build_tree(1,0,le-1);
        for(int i=0;i<q;i++){
            int s;
            cin>>s;
            if(f[s]!=0)
                cout<<"YES"<<endl;
            else
                cout<<"NO"<<endl;
        }
    }
}
View Code
原文地址:https://www.cnblogs.com/sszywq/p/14324644.html