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;
}