今天原来是平安夜啊

感觉这题是道好题。

一个套路枚举权值\(x\),把权值等于\(x\)的设为1,不等于的设为-1,然后问题转化为多少个区间权值和大于。

发现并不是很好做,还有一个套路,用前缀和查分来表示区间。然后就是

\[i<j
\]

\[sum[i]<sum[j]
\]

然后树状数组可以做\(a[i]\leq7\)的数据。

那么\(a[i]\)那么大该怎么办?

考虑我们构建的\(1,-1\)数列中连续-1的数列很多。

然后这些连续-1不会互相影响的贡献,然后我们考虑直接算出这些连续-1的贡献。

设这段连续-1的两端的sum为\(l,r\)。贡献为:

\[\sum_{i=l}^r\sum_{j=-inf}^{i-1}cnt[j]=(r-l+1)*\sum_{i=-inf}^{l-1}cnt[i]+\sum_{i=l}^r(r-i)*cnt[i]
\]

然后我们在线段树上维护\(i\)和\(cnt[i]\),然后用线段树可以把这个-1序列\(logn\)处理掉。

然后每一个1单独处理,最后总复杂度\(O(nlogn)\)

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<vector>
using namespace std;
#define int long long
#define mid ((l+r)>>1)
#define ls now<<1
#define rs now<<1|1
const int N=501000;
vector<int> vec[N];
int sum[N*2*5],sumi[N*2*5],lazy[N*2*5],a[N],b[N],last,lastsum,ans,n;
int read(){
int sum=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){sum=sum*10+ch-'0';ch=getchar();}
return sum*f;
}
void update(int now){
sum[now]=sum[ls]+sum[rs];
sumi[now]=sumi[ls]+sumi[rs];
}
void pushdown(int l,int r,int now){
if(lazy[now]==0)return;
if(l==r)return;
sum[ls]+=(mid-l+1)*lazy[now];
sumi[ls]+=(mid+l)*(mid-l+1)/2*lazy[now];
sum[rs]+=(r-(mid+1)+1)*lazy[now];
sumi[rs]+=(r+mid+1)*(r-(mid+1)+1)/2*lazy[now];
lazy[ls]+=lazy[now];
lazy[rs]+=lazy[now];
lazy[now]=0;
}
void add(int l,int r,int L,int R,int k,int now){
if(R<l||L>r)return;
pushdown(l,r,now);
if(L<=l&&r<=R){
sum[now]+=(r-l+1)*k;
sumi[now]+=(l+r)*(r-l+1)/2*k;
lazy[now]+=k;
return;
}
add(l,mid,L,R,k,ls);
add(mid+1,r,L,R,k,rs);
update(now);
}
int check(int l,int r,int L,int R,int now){
if(R<l||L>r)return 0;
pushdown(l,r,now);
if(L<=l&&r<=R)return sum[now];
return check(l,mid,L,R,ls)+check(mid+1,r,L,R,rs);
}
int checki(int l,int r,int L,int R,int now){
if(R<l||L>r)return 0;
pushdown(l,r,now);
if(L<=l&&r<=R)return sumi[now];
return checki(l,mid,L,R,ls)+checki(mid+1,r,L,R,rs);
}
signed main(){
n=read();int hh=read();
for(int i=1;i<=n;i++)a[i]=read(),b[i]=a[i];
sort(b+1,b+1+n);
int tot=unique(b+1,b+1+n)-b-1;
for(int i=1;i<=n;i++)a[i]=lower_bound(b+1,b+1+tot,a[i])-b;
for(int i=1;i<=n;i++)vec[a[i]].push_back(i);
add(1,2*n,n,n,1,1);
for(int i=1;i<=tot;i++){
vec[i].push_back(n+1);
last=0;lastsum=0;
for(int j=0;j<vec[i].size();j++){
int L=vec[i][j]-last-1;
int l=lastsum-L;
int r=lastsum-1;
if(vec[i][j]!=last+1){
ans+=L*check(1,2*n,1,l+n-1,1);
ans+=(r+n)*check(1,2*n,l+n,r+n,1);
ans-=checki(1,2*n,l+n,r+n,1);
add(1,2*n,l+n,r+n,1,1);
}
if(vec[i][j]==n+1)continue;
ans+=check(1,2*n,1,l+n,1);
add(1,2*n,l+1+n,l+1+n,1,1);
last=vec[i][j];lastsum=l+1;
}
last=0;lastsum=0;
for(int j=0;j<vec[i].size();j++){
int L=vec[i][j]-last-1;
int l=lastsum-L;
int r=lastsum-1;
if(vec[i][j]!=last+1)add(1,2*n,l+n,r+n,-1,1);
if(vec[i][j]==n+1)continue;
add(1,2*n,l+1+n,l+1+n,-1,1);
last=vec[i][j];lastsum=l+1;
}
}
printf("%lld\n",ans);
return 0;
}

luogu P4062 [Code+#1]Yazid 的新生舞会(线段树+套路)的更多相关文章

  1. 【BZOJ5110】[CodePlus2017]Yazid 的新生舞会 线段树

    [BZOJ5110][CodePlus2017]Yazid 的新生舞会 Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一 ...

  2. P4062 [Code+#1]Yazid 的新生舞会

    思路:分治 提交:2次 错因:数组开小 题解: 我们枚举一下众数\(x\). 设\(s[n]=\sum_{i=1}^n [a[i]==x]\) 那么对于区间\((l,r]\),有\(s[r]-s[l] ...

  3. 洛谷 P4062 - [Code+#1]Yazid 的新生舞会 的线性做法

    洛谷题面传送门 一个线性做法. \(n\log n\) 解法可以戳这里查看 首先回顾一下 \(n\log n\) 解法的过程:我们对于每一个数 \(x\),考察其出现位置,设为 \(t_1,t_2,t ...

  4. 洛谷 P4062 - [Code+#1]Yazid 的新生舞会(权值线段树)

    题面传送门 题意: 给出一个序列 \(a\),求 \(a\) 有多少个子区间 \([l,r]\),满足这个区间中出现次数最多的数出现次数 \(>\dfrac{r-l+1}{2}\) \(1 \l ...

  5. BZOJ.5110.[CodePlus2017]Yazid 的新生舞会(线段树/树状数组/分治)

    LOJ BZOJ 洛谷 又来发良心题解啦 \(Description\) 给定一个序列\(A_i\).求有多少个子区间,满足该区间众数出现次数大于区间长度的一半. \(n\leq5\times10^5 ...

  6. 【线段树】【P4062】 [Code+#1]Yazid 的新生舞会

    Description 给定一个长度为 \(n\) 的序列,求有多少子区间满足区间众数严格大于区间长度的一半.如果区间有多个出现次数最多且不同的数则取较小的数为众数. Limitation 对于全部的 ...

  7. [题解] [Code+#1]Yazid 的新生舞会

    题面 题解 upd : \(cnt_i\) 代表值为 \(i\) 的个数 我们可以暴力枚举众数 \(k\) 把等于 \(k\) 的赋值成 1 , 不等于 \(k\) 的赋值成 -1 这样原序列就变成了 ...

  8. 「CodePlus 2017 11 月赛」Yazid 的新生舞会(树状数组/线段树)

    学习了新姿势..(一直看不懂大爷的代码卡了好久T T 首先数字范围那么小可以考虑枚举众数来计算答案,设当前枚举到$x$,$s_i$为前$i$个数中$x$的出现次数,则满足$2*s_r-r > 2 ...

  9. luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树)(主席树)

    luogu P3919 [模板]可持久化数组(可持久化线段树/平衡树) 题目 #include<iostream> #include<cstdlib> #include< ...

随机推荐

  1. JavaScript中必记英语单词及含义

    reflow[ri'flo]:回流,重构(通过css改变页面的结构,比如一行元素,其中一个元素的高改变了,那么其他元素的位置也都会改变) repaint['ripent]:重绘(只改变页面的样式,比如 ...

  2. luoguP1390 公约数的和 数学推导_双倍经验

    Code: #include <bits/stdc++.h> #include <tr1/unordered_map> #define setIO(s) freopen(s&q ...

  3. HTML中使用 js 添加 data-toggle

    情况:<li class="active"><a href="#server1" data-toggle="tab"> ...

  4. ajax常用知识

     同源地址:任意两个地址中的协议,域名,端口相同,称为同源地址 同源策略:  是浏览器的一种基本安全策略                       不允许对非同源地址进行请求(ajax)       ...

  5. [读书笔记] R语言实战 (十三) 广义线性模型

    广义线性模型扩展了线性模型的框架,它包含了非正态的因变量分析 广义线性模型拟合形式: $$g(\mu_\lambda) = \beta_0 + \sum_{j=1}^m\beta_jX_j$$ $g( ...

  6. zabbix_get 获取agnet端mysql数据失败

    问题 在使用zabbix_get获取agent端的mysql数据时,总是报错,ERROR 2002 (HY000): Can't connect to local MySQL server throu ...

  7. Mysql干货收集

    mysql优化:https://www.cnblogs.com/duanxz/tag/mysql/default.html?page=1

  8. Linux赛车游戏 SuperTuxKart 1.0 正式发布

    SuperTuxKart是一款受Mario Kart(马里奥赛车)启发并以Linux/Tux为主题的开源赛车游戏,经过12年多的开发,已经达到1.0版本.并且确定这个版本确实是一个重要的里程碑. Su ...

  9. C/C++中的段错误(Segmentation fault)[转]

    Segment fault 之所以能够流行于世,是与Glibc库中基本所有的函数都默认型参指针为非空有着密切关系的. 来自:http://oss.lzu.edu.cn/blog/article.php ...

  10. web前端项目规范

    项目目录规范 . ├─ css ├─ component ├─ img ├─ js ├─ page ├─ test ├─ package.json ├─ README.md css 存放样式类文件,且 ...