[vijos1459][车展]

题目链接

思路

首先可以证明当这个高度是中位数的时候耗费时间是最少了。所以可以\(n^2log(n)\)用一个treap预处理出每个区间的中位数。
然后就是知道了中位数怎么计算答案的问题。
然后发现暴力n*m的扫能过而且跑的还不慢
但是作为一个正直善良的OIER我还是用\(n^2log(n)\)做的。
发现用中位数减去比他小的在加上比中位数大的减去中位数,恰好可以把中位数给抵消掉(并不是都可以完全抵消掉,这个可以根据中位数的位置算一下),然后发现其实就是用那些比中位数大的数减去比中位数小(或者等于)的数,要不要再加回来一个中位数要特判一下。

代码

//寻找每个区间内的中位数
/*
* @Author: wxyww
* @Date:   2018-12-02 10:36:55
* @Last Modified time: 2018-12-02 14:22:15
*/
#include<cstdio>
#include<iostream>
#include<cstdlib>
#include<cmath>
#include<ctime>
#include<bitset>
#define ls TR[cur].ch[0]
#define rs TR[cur].ch[1]
using namespace std;
typedef long long ll;
const int N = 2010;
ll read() {
   ll x = 0,f = 1;char c = getchar();
   while(c < '0' || c > '9') {
      if(c == '-') f = -1;
      c = getchar();
   }
   while(c >= '0' && c <= '9') {
      x = x * 10 + c - '0';
      c = getchar();
   }
   return x * f;
}
struct node {
   int ch[2],id,val,siz,cnt;
   ll VAL;
   void CLEAR() {
      ch[1] = ch[0] = id = val = siz = cnt = VAL = 0;
   }
}TR[N];
void up(int cur) {
   TR[cur].siz = TR[ls].siz + TR[rs].siz + TR[cur].cnt;
   TR[cur].VAL = TR[ls].VAL + TR[rs].VAL + TR[cur].val * TR[cur].cnt;
}
void rotate(int &cur,int f) {
   int son = TR[cur].ch[f];
   TR[cur].ch[f] = TR[son].ch[f ^ 1];
   TR[son].ch[f ^ 1] = cur;
   up(cur);cur = son;up(cur);
}
int tot;
void insert(int &cur,int val) {
   if(!cur) {
      cur = ++tot;
      TR[cur].val = val;
      TR[cur].id = rand();
      TR[cur].siz = TR[cur].cnt = 1;
      TR[cur].VAL = val;
      TR[cur].ch[1] = TR[cur].ch[0] = 0;
      return;
   }
   if(val == TR[cur].val) {TR[cur].cnt++;TR[cur].siz++;TR[cur].VAL += val;return;}
   int d = val > TR[cur].val;
   insert(TR[cur].ch[d],val);
   up(cur);
   if(TR[TR[cur].ch[d]].id < TR[cur].id) rotate(cur,d);
}
int kth(int cur,int now) {
   while(1) {
      if(now > TR[ls].siz + TR[cur].cnt) now -= TR[ls].siz + TR[cur].cnt,cur = rs;
      else if(now <= TR[ls].siz) cur = ls;
      else return TR[cur].val;
   }
}
int rt,n,a[N];
ll sum[N],ans[N][N];
ll find(int cur,int val) {
   if(!cur) return 0;
   if(val >= TR[cur].val) return find(rs,val) + TR[ls].VAL + TR[cur].val * TR[cur].cnt;
   return find(ls,val);
}
int main() {
   n = read();
   int m = read();
   for(int i = 1;i <= n;++i) a[i] = read(),sum[i] = sum[i-1] + a[i];
   for(int i = 1;i <= n;++i) {
      rt = tot = 0;
      for(int j = i;j <= n;++j) {
         insert(rt,a[j]);
         int z = kth(rt,(j - i + 2) / 2);
         ll k = find(rt,z);
         if((j - i) & 1)   ans[i][j] = sum[j] - sum[i-1] - k * 2;
         else ans[i][j] = sum[j] - sum[i-1] - k * 2 + z;
      }
   }
   ll anss = 0;
   while(m--) anss += ans[read()][read()];
   cout<<anss;
   return 0;
}

一言

易碎的 骄傲着 那也曾是我的模样。

全部评论

相关推荐

12-08 16:04
门头沟学院 Java
本人本科末9,今年大三。大一大二一直玩,什么都没学到,在大学混日子混了两年,每天不是在打农就是在steam。大三开学时一个和自己玩的好的同学去实习了,才发现自己白白浪费了两年的时间,如果真不冲一下就真去京东,阿里,美团送外卖了今年9月份开始学Java,一开始一直跟着黑马视频看,后面发现看视频效率太低了,时间根本不够,就开始主要看文档和看书了。这几个月一直在学,真的尽力了,希望暑期前能找一份好点的实习。我简历上面的项目大多没有指标,但是实际上我是真没多少时间去做项目,我基本主要是动手只做了外卖和天机,黑马点评和12306我都是只是看了项目。主要是自己的时间真的不多,但是这样子自己的代码能力确实比较差。而且自己也没有做过实际的工程,我顶多用jmeter测试一下接口tps啥的,比如使用Redis管道提升了一点性能,减少Redis交互,这种值得写上去吗?需不需要具体到某些数字求求各位佬给一些建议,看看简历怎么优化?项目介绍是不是不够详细?没有具体到业务方面。项目会不会提到大致实现原理导致面试官一看简历就知道怎么实现就没有问的欲望?专业技能一些字段是不是要加粗,是不是写太啰嗦了?有没有必要压缩内容变成一页?两页的话是不是都要把两页填地满满的。
给秋招一个交代:一页简历最好,网上做的项目放面试官眼里都是玩具,简历上不需要强调有什么难点,记住就行防止真的问。然后背八股,多投多面试就行
点赞 评论 收藏
分享
牛至超人:把哈工大,再加大加粗,看见闪闪发光的哈工大字样,面试官直接流口水
投递字节跳动等公司6个岗位
点赞 评论 收藏
分享
评论
点赞
收藏
分享

创作者周榜

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