杭电多校赛三 Find the answer 离散化

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6609

题意:给你一个长为n(2e5+7)的数字序列和一个数字m(1e9),对从1开始的每段区间分析(1-1,1-2...1-n),要求区间和小于m,你可以将每段区间除右端点的数置为0,每段区间输出已经将多少数置为0了

分析:对于第i个位置,怎样选择数字才会使满足条件情况下选择数字数目最少呢?很容易想到,需要选择前i1个数中较大的数字,使其变为0

基于这个思想,如果我们对于每个位置i都暴力去找最大的前几个数,显然会TLE!

可以注意到,题目可以转化为前i-1个数中最多选出多少个数字和W[i]相加使得其和小于等于m(很容易想到,选择较小的数才会使选的数最多)。

转化之后就很容易想到用线段树来维护了。 我们对给定数组进行离散化,对于离散化之后的数组建立一颗线段树,线段树上的每个节点记录区间之和以及区间内数字个数。时间复杂度:N*log(N)

代码分析:一开始并不将线段树初始化完毕,而是一步步初始化,init()方法中nn不断乘2是为了将索引变到最下面的结点一层(如果结点一层完全的话,子节点的数目是前面所有分支数加一,因为这是一个以2为公比,1为首项的等比数列。这也是后面调用update方法时nn-1的原因),所有我们一般初始化线段树是扩大四倍。

代码中用到了离散化,记得好好看一看。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;//这个数是1e9数量级的,且可以用memset函数
const int maxn=2e5+7;
const double pi=acos(-1);
const int mod=1e9+7;
ll sum[4*maxn],sums[4*maxn];//分别是区间和,以及区间内数字的个数
ll qzh[maxn];//前缀和
struct node{
    ll v,id;
    bool operator <(const node &x) const{
        if(v==x.v) return id<x.id;
        return v>x.v;
    }
}a[maxn],b[maxn];
int ans=0,nn;//ans用来记录答案
void init(int n){
    nn=1;
    while(nn<n) nn*=2;
}
void query(int k,int l,int r,ll u){
    int mid=(l+r)/2;
    if(u==0) return ;
    if(r-l==1){
        ans+=sums[k];
        return ;
    }
    if(sum[2*k]<=u) u-=sum[2*k],ans+=sums[2*k],query(k*2+1,mid,r,u);//如果左边的不够减,就搜右边的
    else{
        query(k*2,l,mid,u);//否则,就继续往左边搜
    }
}
void update(int k,int v){
    if(k==0)return;
    sum[k]+=v;
    sums[k]++;
    update(k/2,v);
}
int main(){
    int Q;scanf("%d",&Q);
    while(Q--){
        memset(sum,0,sizeof(sum));
        memset(sums,0,sizeof(sums));
        int n;ll m;scanf("%d %lld",&n,&m);
        init(n);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i].v);
            b[i].id=i;
            b[i].v=a[i].v;
            qzh[i]=qzh[i-1]+a[i].v;
        }
        sort(b+1,b+1+n);
        for(int i=1;i<=n;i++){
            a[b[i].id].id=i;
        }//离散化,目的就是使a数组的id标的是其在a数组中的大小排名
        for(int i=1;i<=n;i++){
            ll t=qzh[i]-m;
            ans=0;
            if(t>0) {
                query(1,1,nn,t);
            }
            printf("%d ",ans);
            update(a[i].id+nn-1,a[i].v);
        }
        cout<<endl;
    }
    return 0;
}
#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int inf=0x3f3f3f3f;//这个数是1e9数量级的,且可以用memset函数
const int maxn=2e5+7;
const double pi=acos(-1);
const int mod=1e9+7;
ll sum[4*maxn],sums[4*maxn];//分别是区间和,以及区间内数字的个数
ll qzh[maxn];//前缀和
struct node{
    ll v,id;
    bool operator <(const node &x) const{
        if(v==x.v) return id<x.id;
        return v>x.v;
    }
}a[maxn],b[maxn];
int ans=0,nn;//ans用来记录答案
void init(int n){
    nn=1;
    while(nn<n) nn*=2;
}
void query(int k,int l,int r,ll u){
    int mid=(l+r)/2;
    if(u==0) return ;
    if(r-l==1){
        ans+=sums[k];
        return ;
    }
    if(sum[2*k]<=u) u-=sum[2*k],ans+=sums[2*k],query(k*2+1,mid,r,u);//如果左边的不够减,就搜右边的
    else{
        query(k*2,l,mid,u);//否则,就继续往左边搜
    }
}
void update(int k,int v){
    if(k==0)return;
    sum[k]+=v;
    sums[k]++;
    update(k/2,v);
}
int main(){
    int Q;scanf("%d",&Q);
    while(Q--){
        memset(sum,0,sizeof(sum));
        memset(sums,0,sizeof(sums));
        int n;ll m;scanf("%d %lld",&n,&m);
        init(n);
        for(int i=1;i<=n;i++){
            scanf("%lld",&a[i].v);
            b[i].id=i;
            b[i].v=a[i].v;
            qzh[i]=qzh[i-1]+a[i].v;
        }
        sort(b+1,b+1+n);
        for(int i=1;i<=n;i++){
            a[b[i].id].id=i;
        }//离散化,目的就是使a数组的id标的是其在a数组中的大小排名
        for(int i=1;i<=n;i++){
            ll t=qzh[i]-m;
            ans=0;
            if(t>0) {
                query(1,1,nn,t);
            }
            printf("%d ",ans);
            update(a[i].id+nn-1,a[i].v);
        }
        cout<<endl;
    }
    return 0;
}

原文地址:https://www.cnblogs.com/qingjiuling/p/11269260.html

时间: 2024-11-08 20:31:52

杭电多校赛三 Find the answer 离散化的相关文章

hdu 5326 Work(杭电多校赛第三场)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5326 Work Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 583    Accepted Submission(s): 392 Problem Description It’s an interesting experience to

2018 Multi-University Training Contest 3 杭电多校第三场

躺了几天 终于记得来填坑了 1001 Ascending Rating   (hdoj 6319) 链接:http://acm.hdu.edu.cn/showproblem.php?pid=6319 单调队列 具体有点类似双端队列滑动窗口 题意:在一个队列中 每次都给定一个固定长度的区间 从i=1开始向后移动 每次在这个区间中进行a[i]和a[j]的比较 若a[i]<a[j] count++ 最大值更新为a[j] ,每个区间的最大值和count都分别异或i 求出分别的和 求区间最大值可以比较容易

2019年杭电多校第三场 1011题Squrirrel(HDU6613+树DP)

题目链接 传送门 题意 给你一棵无根树,要你寻找一个根节点使得在将一条边权变为\(0\)后,离树根最远的点到根节点的距离最小. 思路 本题和求树的直径很像,不过要记得的东西有点多,且状态也很多. \(fi[u][0]\)表示在\(u\)这个结点不删边沿着子树方向能到达的最远距离,\(se[u][0]\)为第二远,\(th[u][0]\)为第三远,\(fa[u][0]\)表示沿着父亲方向能到达的最远距离,第二维为\(1\)表示删一条边能到达的距离. 不删边的转移和求树的直径转移方程基本上是一样的,

hdu 5328 Problem Killer(杭电多校赛第四场)

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5328 题目大意:找到连续的最长的等差数列or等比数列. 解题思路:1.等差等比的性质有很多.其中比较重要的一个就是解题关键:如a[i-2],a[i-1],a[i],a[i+1]这个序列.a[i-2],a[i-1],a[i]是等差数列,a[i-1],a[i],a[i+1]也是等差数列.那么a[i-2],a[i-1],a[i],a[i+1]就是等差数列.  2. 等比数列也是一样的~~只要根据这个性质就

杭电多校第三场 A Ascending Rating

Problem Description Before the start of contest, there are n ICPC contestants waiting in a long queue. They are labeled by 1 to n from left to right. It can be easily found that the i-th contestant's QodeForces rating is ai.Little Q, the coach of Qua

2019杭电多校第三场 1004 Distribution of books

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=6606 考虑二分答案,我们二分一个值\(x\),那么要怎么来验证这个答案是否可行,考虑dp求解,设\(dp[i]\)为前i个在答案为\(x\)的情况下划分最最多组数,那么若\(dp[n] \geq k\) 则这个x可行, 很显然可以看出\(x\)是单调的,所以二分. \[dp[i] = max(dp[j]) + 1 (sum[i] - sum[j-1] \leq x)\] 如果直接采用暴力枚举的话复杂

2019杭电多校第三次hdu6609 Find the answer(线段树)

Find the answer 题目传送门 解题思路 要想变0的个数最少,显然是优先把大的变成0.所以离散化,建立一颗权值线段树,维护区间和与区间元素数量,假设至少减去k才能满足条件,查询大于等于k的最少数量即可. 代码如下 #include <bits/stdc++.h> #define INF 0x3f3f3f3f using namespace std; typedef long long ll; inline int read(){ int res = 0, w = 0; char c

2019杭电多校第三场 1008 K-th Closest Distance

题目链接 http://acm.hdu.edu.cn/showproblem.php?pid=6621 考虑主席树,我们先将所有值离散化之后建主席树.对于每个查询\(s,t,p,k\) 我们考虑二分一个值\(mid\),考虑当前区间内,\([p-mid, p+mid]\)的值有多少个,很显然这是符合单调性的,那么我们只需要每次判断即可.时间复杂度\(O(nlog^2n)\) #include <bits/stdc++.h> #define pii pair<int, int> #d

2019 杭电多校 第三场

2019 Multi-University Training Contest 3 补题链接:2019 Multi-University Training Contest 3 1002 Blow up the city (HDU-6604) 题意 给定 \(n\) 个点和 \(m\) 条边的有向无环图,给出 \(q\) 次询问,每个询问给出 \(a\) 和 \(b\),求有多少个点,满足该点删去后 \(a\) 和 \(b\) 中至少一个点不能到达出度为 \(0\) 的点. 题解 支配树/灭绝树 拓