3.5 美团 区间问题 100%

题目就是给n个数字,m个操作,可以区间add,也可以区间query求和

问这n个数字怎么排出来,可以使得sum{query} 最大


解法:
题目前一半就是线段树模板题,处理区间的增长和求和

后一段才是精华,需要知道怎么排才能使得和最大

要使得和最大,那么某个位置的被查询次数越多,说明这个位置的数的贡献值越大。于是得出最大的数应该放在查询次数最多的那个位置上

所以就是先算每个位置被算了几次,对整个位置的次数进行从小到大排序,依次把原数据也从小到大放进去。然后套线段树即可

代码:(变量有点丑,轻喷)
#include <iostream>
#include <queue>
#include <stdio.h>
#include "map"
#include "string"
#include "string.h"
#include "stack"
#include<algorithm>


using namespace std;



#define MAX 5002

#define LL long long

int tree[4*MAX];
int lz[4*MAX];
int a[MAX];  //原数组

int l[MAX];

int r[MAX];

int x[MAX];  //操作标志,1表示求和,2表示增长
int z[MAX];   // 2的时候的加数

int last[MAX];

struct Node{
    int data;
    int index;
} origin[MAX];  //位置数据,最开始data都是0,index就是位置


bool compare(Node a,Node b)
{
    return a.data <b.data ;   //对data排序
} //< 升序    >降序


void init(){
    memset(tree,0,sizeof(tree));
}


void push_down(int node,int l,int r){
    if(lz[node]){
        int mid = (l+r) / 2;
        lz[node*2] += lz[node];
        lz[node*2 + 1] += lz[node];
        // 注意线段树的数据更新方式要一致
        tree[node*2] += 1LL*(mid - l + 1)*lz[node];
        tree[node*2 + 1] += 1LL*(r - mid)*lz[node];
        lz[node] = 0;
    }
}


// 区间查找
LL query_range(int node,int L,int R,int l,int r){
    if(l <= L && r >= R) return tree[node];
    push_down(node,L,R);
    int mid = (L+R) / 2;
    LL sum = 0;
    if(mid >= l) sum += query_range(node*2,L,mid,l,r);
    if(mid < r) sum += query_range(node*2 + 1,mid+1,R,l,r);
    return sum;
}


void update_range(int node,int l,int r,int L,int R,int add){
    if(l <= L && r >= R){
        lz[node] += 1LL*add;
        tree[node] += 1LL*(R - L + 1)*add; // 更新方式
        return;
    }
    push_down(node,L,R);
    int mid = (L+R) / 2;
    if(mid >= l) update_range(node*2,l,r,L,mid,add);
    if(mid < r) update_range(node*2 + 1,l,r,mid+1,R,add);
    tree[node] = tree[node*2] + tree[node*2 + 1];
}



void build(int node,int l,int r) {
    if (l == r) { // 到达叶子节点,赋值
        tree[node] = last[l];
        return;
    }
    int mid = (l + r) / 2;
    build(node * 2, l, mid); // 进入子树开始递归
    build(node * 2 + 1, mid + 1, r);
    tree[node] = tree[node * 2] + tree[node * 2 + 1]; // 回溯

}


int main() {
    int n, m;
    cin >> n >> m;

    init();
    for(int i=1;i<=n;i++){
        cin>>a[i];

    }

    for(int i =1;i<=n;i++){
        origin[i].data = 0;
        origin[i].index = i;
    }

    //build(1, 1, n);
    
    
    for(int i=0;i<m;i++){
        cin >> x[i] >> l[i] >> r[i];
        if(x[i] == 1){
            for(int j=l[i]; j<=r[i]; j++){
                origin[j].data = origin[j].data+1;
            }
        } else {
            cin >> z[i];

        }

    }


    sort(a+1, a+n+1);
    sort(origin+1, origin+n+1, compare);


    for(int i=1;i<=n;i++){
        //cout << a[i] <<endl;
        //cout << origin[i].data << " " << origin[i].index << endl;
        //cout << origin[i].index << endl;

        last[origin[i].index] = a[i];
    }


    //cout << endl;
    build(1, 1, n);


    LL ans = 0;
    for(int i=0;i<m;i++){

        if(x[i] == 1){
            long long sum = query_range(1, 1, n, l[i], r[i]);
            ans = ans + sum;
            //cout << sum << endl;
        } else {

            update_range(1, l[i], r[i], 1, n, z[i]);
        }

    }

    cout << ans <<endl;

    return 0;
}

可以帮答疑、做题,可私信

#美团笔试##美团##笔经#
全部评论
知道后一段就行了,前一段不用线段树直接暴力也能过😂
2 回复 分享
发布于 2022-03-05 14:06
我也是这思路,只a了0.6。。。
点赞 回复 分享
发布于 2022-03-05 14:35

相关推荐

用户64975461947315:这不很正常吗,2个月开实习证明,这个薪资也还算合理,深圳Java好多150不包吃不包住呢,而且也提前和你说了没有转正机会,现在贼多牛马公司骗你说毕业转正,你辛辛苦苦干了半年拿到毕业证,后面和你说没hc了😂
点赞 评论 收藏
分享
评论
点赞
7
分享

创作者周榜

更多
牛客网
牛客网在线编程
牛客网题解
牛客企业服务