HDU 6609 + weight discrete segment tree

The meaning of problems

Has a length \ (n-\) of the array W is;

For each \ (I \) ( \ (. 1 <= I <= n-\) ), you can select any number of elements W is [K] ( \ (. 1 <= K <I \) ), their value is changed to 0, so that the \ (\ sum_ {J}. 1 ^ = {I}. 1-W is [J] <= m \) ,

So n digital outputs, for each representative of a \ (I \) , to meet the above conditions, the number of elements to change at least.

idea

To do this problem, I have been thinking about how greedy, then been not think.

Generally the first reaction should be to change the big elements, but can also be considered to retain small elements.

+ Weights can be discrete segment tree.

After discrete, with a weight segment tree maintenance front \ (i-1 \) elements in each element appears many times.

Tree line elements within each section each node records there have been many times, and all the elements within each interval and.

For each \ (I \) , we first \ (i-1 \) element as much as possible to find the elements which make them is not greater than \ (mW [I] \) .

When queried,

If a node is less than \ (mW [I] \) , then the answer is directly coupled with the number of elements on the interval, i.e., the element sections are retained.

Otherwise, if the left subtree is greater than \ (mW [i] \) , then the left subtree find what number should be retained,

If the left subtree and smaller than \ (mW [i] \) of all elements ,, then left sub-tree retention and looking in the right subtree which elements need that query in the right subtree is not greater than \ (mW [i] - \ number sum left subtree \) .

Code

#include<stdio.h>
#include<vector>
#include<algorithm>

typedef long long ll;
const int MAXN = 200100;
class Node{
    public:
        int l, r, num;//l,r是区间的范围,num是区间上的数的出现次数
        ll val;//val是区间上的数的和
        Node *lson, *rson;//左右子树
        Node(int _l, int _r);
        int mid();
        int query(int k);
        void update(int pos, int _val);
        void clear();

};
Node::Node(int _l, int _r){//建线段树
    l = _l, r = _r, val = 0, num = 0;
    if(l != r){
        lson = new Node(l, mid());
        rson = new Node(mid()+1, r);
    }
}
void Node::clear(){//删除线段树
    if(l!=r){
        lson->clear();
        rson->clear();
        delete lson;
        delete rson;
    }
}
int Node::mid(){//求l和r的平均值
    return (l+r)>>1;
}
int Node::query(int _val){//查询,在不大于_val的情况下,应该保留哪些数字
    if(val <= _val) return num;//保留整个区间,直接返回num
    if(l == r)  return (_val*num/val);//区间范围为1(即只有一个数)的时候,返回能保留多少个这个数字
    if(lson->val>_val) return lson->query(_val);
    else return lson->num+rson->query(_val-lson->val);//保留左子树上的所有数字,查询右子树
}
void Node::update(int pos, int _val){
    if(l == r){
        val+=_val,num++;
        return;
    }
    if(pos<l || pos>r) return;

    if(pos<=mid()) lson->update(pos, _val);
    else rson->update(pos, _val);
    num = lson->num+rson->num;
    val = lson->val+rson->val;
}
int W[MAXN], uniqueW[MAXN];

int main(){
    int t;
    scanf("%d", &t);
    while(t--){
        int maxW, n, m;
        Node *seqTree = 0;
        scanf("%d%d", &n, &m);
        for(int i = 1; i <= n; ++i)
            scanf("%d", W+i), uniqueW[i] = W[i];
        std::sort(uniqueW+1, uniqueW+n+1);//离散化
        maxW = std::unique(uniqueW+1, uniqueW+n+1)-(uniqueW+1);
        seqTree = new Node(1, maxW);//建立一颗空的线段树,一开始没有任何的元素
        for(int i = 1; i <= n ; ++i){
            int pos = std::lower_bound(uniqueW+1, uniqueW+maxW+1, W[i])-(uniqueW);//找W[i]离散化之后的位置
            printf("%d ", i-seqTree->query(m-W[i])-1);//query返回的是保留的数,i-query-1就是应该改变的数
            seqTree->update(pos, uniqueW[pos]);//把W[i]插入线段树
        }
        seqTree->clear();//删除一下,以免mle
        printf("\n");
    }
}

Guess you like

Origin www.cnblogs.com/Omicron-Pavo/p/11272286.html