(很久之前刷的题现在看起来十分陌生a)

题意:

给你一个长度为n的序列A,定义一个区间$[l,r]$是“新生舞会的”当且仅当该区间的众数次数严格大于$\frac{r-l+1}{2}$,求有多少子区间是“新生舞会的”。

$n\leq 500000,0\leq A_{i} \leq n-1$

题解:

关于区间众数的问题一般有一个套路:枚举众数后转换成区间求和问题。

考虑枚举众数k,若将序列中等于k的元素视作+1,其他视作-1,那么“新生舞会的“区间必然满足区间之和大于0。

问题变成了如何快速求出有多少个区间之和大于0的子区间。

考虑枚举右端点r并记录前缀和sum,那么要求的就是有多少左端点l满足$sum[l]<sum[r]$

直接用一个线段树维护即可。(树状数组也行,但跟后面的做法无关)

但是这样复杂度是$O(n^2)$的,无法通过本题。

注意到枚举众数后,序列中1的个数的总数是n。

容易发现连续的-1总数也为n,那么我们考虑将一段连续的-1一起考虑。

假设一段-1的起点是l,终点是r,sum值i出现了$cnt(i)$次,那么这段-1作为右端点时对答案的贡献之和就是

$\sum_{i=l}^{r}{\sum_{j=-inf}^{i-1}{cnt(j)}}$

$=\sum_{j=-inf}^{r-1}{\sum_{i=max(j+1,l)}^{r}{cnt(j)}}$

$=(r-l+1)\times{\sum_{i=-inf}^{l-1}{cnt(i)}}+\sum_{i=l}^{r}{(r-i)\times cnt(j)}$

那么直接维护两个线段树表示$cnt(i)$和$cnt(i)\times i$即可。

对于每段-1,统计答案后在其对应值域区间加,然后计算单个1的贡献即可。

复杂度$O(nlogn)$,比较难写,特别是清空线段树时需要注意clear标记的写法。

代码:

#include<bits/stdc++.h>
#define maxn 2000005
#define maxm 500005
#define inf 0x7fffffff
#define ll long long using namespace std;
ll N,M,A[maxn],B[maxn],lz1[maxn<<],lz2[maxn<<];
ll s1[maxn<<],s2[maxn<<],vis[maxn];
vector<ll> pos[maxn]; inline ll read(){
ll x=,f=; char c=getchar();
for(;!isdigit(c);c=getchar()) if(c=='-') f=-;
for(;isdigit(c);c=getchar()) x=x*+c-'';
return x*f;
} inline void pushup1(ll k){s1[k]=s1[k<<]+s1[k<<|];}
inline void pushdown1(ll len,ll k){
if(k>=(maxn<<)) return;
if(!lz1[k]) return;
if(lz1[k]==-){
s1[k<<]=s1[k<<|]=;
lz1[k<<]=lz1[k<<|]=-;
lz1[k]=; return;
}
if(lz1[k<<]==-) pushdown1(len+>>,k<<),lz1[k<<]=,s1[k<<]=;
if(lz1[k<<|]==-) pushdown1(len>>,k<<|),lz1[k<<|]=,s1[k<<|]=;
lz1[k<<]+=lz1[k],lz1[k<<|]+=lz1[k];
s1[k<<]+=lz1[k]*((len+)>>),s1[k<<|]+=lz1[k]*((len)>>);
lz1[k]=; return;
}
inline ll qry1(ll x,ll y,ll l,ll r,ll k){
pushdown1(r-l+,k);
if(x<=l && r<=y) return s1[k];
ll mid=(l+r)>>,ans=;
if(x<=mid) ans+=qry1(x,y,l,mid,k<<);
if(y>mid) ans+=qry1(x,y,mid+,r,k<<|);
return ans;
}
inline void upd1(ll x,ll y,ll l,ll r,ll k){
pushdown1(r-l+,k);
if(x<=l && r<=y){s1[k]+=(r-l+),lz1[k]++;return;}
ll mid=(l+r)>>;
if(x<=mid) upd1(x,y,l,mid,k<<);
if(y>mid) upd1(x,y,mid+,r,k<<|);
pushup1(k); return;
} inline void pushup2(ll k){s2[k]=s2[k<<]+s2[k<<|];}
inline ll dc(ll x,ll y){return (x+y)*(y-x+)/;}
inline void pushdown2(ll l,ll r,ll k){
if(k>=(maxn<<)) return;
if(!lz2[k]) return;
if(lz2[k]==-){
s2[k<<]=s2[k<<|]=;
lz2[k<<]=lz2[k<<|]=-;
lz2[k]=; return;
}
ll mid=(l+r)>>;
if(lz2[k<<]==-) pushdown2(l,mid,k<<),lz2[k<<]=,s2[k<<]=;
if(lz2[k<<|]==-) pushdown2(mid+,r,k<<|),lz2[k<<|]=,s2[k<<|]=;
lz2[k<<]+=lz2[k],lz2[k<<|]+=lz2[k];
s2[k<<]+=lz2[k]*dc(l,mid),s2[k<<|]+=lz2[k]*dc(mid+,r);
lz2[k]=; return;
}
inline ll qry2(ll x,ll y,ll l,ll r,ll k){
pushdown2(l,r,k);
if(x<=l && r<=y) return s2[k];
ll mid=(l+r)>>,ans=;
if(x<=mid) ans+=qry2(x,y,l,mid,k<<);
if(y>mid) ans+=qry2(x,y,mid+,r,k<<|);
return ans;
}
inline void upd2(ll x,ll y,ll l,ll r,ll k){
pushdown2(l,r,k);
if(x<=l && r<=y){s2[k]+=dc(l,r),lz2[k]++;return;}
ll mid=(l+r)>>;
if(x<=mid) upd2(x,y,l,mid,k<<);
if(y>mid) upd2(x,y,mid+,r,k<<|);
pushup2(k); return;
} inline ll calc(ll x){
ll ans=,sum=N; pos[x].push_back(N+);
for(ll i=;i<pos[x].size()-;i++){
ll lp=pos[x][i]+,rp=pos[x][i+]-;
if(pos[x][i]!=) sum++;
ans+=qry1(,sum-,,M,);
ll tp=qry1(,sum-,,M,);
upd1(sum,sum,,M,),upd2(sum,sum,,M,);
if(lp<=rp){
ll l=sum-(rp-lp+),r=sum-; sum-=(rp-lp+);
ll num=(l==)?:(qry1(,l-,,M,)*(r-l+))+((r)*qry1(l,r-,,M,)-qry2(l,r-,,M,));
ans+=num,upd1(l,r,,M,),upd2(l,r,,M,);
}
}
s1[]=s2[]=,lz1[]=lz2[]=-;
return ans;
} int main(){
N=read(),M=(N<<|); ll not_used=read();
for(ll i=;i<=N;i++) A[i]=read()+;
for(ll i=;i<=N;i++)
if(!vis[A[i]]) vis[A[i]]=,pos[A[i]].push_back();
for(ll i=;i<=N;i++) pos[A[i]].push_back(i);
memset(vis,,sizeof(vis)); ll ans=;
for(ll i=;i<=N;i++)
if(!vis[A[i]]) vis[A[i]]=,ans+=calc(A[i]);
printf("%lld\n",ans);
return ;
}

Yazid

[loj 6253] Yazid的新生舞会的更多相关文章

  1. [LOJ 6253] Yazid 的新生舞会

    link $solution:$ 不知道为什么别人的代码能写的非常短,难道就是写差分的好处? 这种题肯定是算每个众数的贡献,考虑通过暴力众数求出个数. 现在考虑众数 $x$ ,则在序列 $a$ 中将等 ...

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

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

  3. bzoj5110: [CodePlus2017]Yazid 的新生舞会

    Description Yazid有一个长度为n的序列A,下标从1至n.显然地,这个序列共有n(n+1)/2个子区间.对于任意一个子区间[l,r] ,如果该子区间内的众数在该子区间的出现次数严格大于( ...

  4. 【bzoj5110】Yazid的新生舞会

    这里是 $THUWC$ 选拔时间 模拟赛的时候犯 $SB$ 了,写了所有的部分分,然后直接跑过了 $4$ 个大样例(一个大样例是一个特殊情况)…… 我还以为我非常叼,部分分都写对了,于是就不管了…… ...

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

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

  6. 【BZOJ5110】[CodePlus2017]Yazid 的新生舞会

    题解: 没笔的时候我想了一下 发现如果不是出现一半次数而是k次,并不太会做 然后我用前缀和写了一下发现就是维护一个不等式: 于是就可以随便维护了

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

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

  8. 【bzoj5110】[CodePlus2017]Yazid 的新生舞会 Treap

    题目描述 求一个序列所有的子区间,满足区间众数的出现次数大于区间长度的一半. 输入 第一行2个用空格隔开的非负整数n,type,表示序列的长度和数据类型.数据类型的作用将在子任务中说明. 第二行n个用 ...

  9. [BZOJ5110]Yazid的新生舞会

    题目大意: 给你一个长度为$n(n\leq 5\times 10^5)$的序列$A_{1\sim n}$.求满足区间众数在区间内出现次数严格大于$\lfloor\frac{r-l+1}{2}\rflo ...

随机推荐

  1. 获取url后的参数、获取a标签的参数

    function getQueryString(name) { var reg = new RegExp("(^|&)" + name + "=([^&] ...

  2. 【Dubbo】带着问题看源码:什么是SPI机制?Dubbo是如何实现的?

    什么是SPI? ​ 在Java中,SPI全称为 Service Provider Interface,是一种典型的面向接口编程机制.定义通用接口,然后具体实现可以动态替换,和 IoC 有异曲同工之妙. ...

  3. mysql 8.0.18 hash join测试(内外网首文)

    CREATE TABLE COLUMNS_hj as select * from information_schema.`COLUMNS`; INSERT INTO COLUMNS_hj SELECT ...

  4. 洛谷 P1969 积木大赛(NOIP2013)

    题目描述春春幼儿园举办了一年一度的“积木大赛”.今年比赛的内容是搭建一座宽度为n的大厦,大厦可以看成由n块宽度为1的积木组成,第i块积木的最终高度需要是hi. 在搭建开始之前,没有任何积木(可以看成n ...

  5. 【C++】C++中的类模板

    基础的类模板 模板类的继承 内部声明定义普通模板函数和友元模板函数 内部声明友元模板函数+外部定义友元模板函数 声明和定义分别在不同的文件(模板函数.模板友元) C++中有一个重要特性,那就是模板类型 ...

  6. ThinkPHP中文字段问题

    转自: https://www.baidu.com/link?url=Ohc9epgQgkNYLwnHqP-jZ9RfIQWW50-iz8-ZMIPLdtCIJHnUpYwQnDLmXzi7Fa110 ...

  7. sklearn的基本使用

    https://cloud.tencent.com/developer/news/58202 简介 今天为大家介绍的是scikit-learn.sklearn是一个Python第三方提供的非常强力的机 ...

  8. Python3基础 is与== 区别

             Python : 3.7.3          OS : Ubuntu 18.04.2 LTS         IDE : pycharm-community-2019.1.3    ...

  9. 安装opencv时ippicv下载超时

    1.手动去下载: github地址为: https://github.com/opencv/opencv_3rdparty/tree/ippicv/master_20151201/ippicv 2.查 ...

  10. Laravel 登录后跳转回登录前浏览的页面

    一.经过 Auth 中间件检查后跳转至登录页面 也就是没有通过 auth 中间件的认证检查,被 auth 中间件拦截后跳转至登录页面.这种情况下,Laravel 默认会在用户登录成功后自动跳转回登录前 ...