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

Description

Yazid有一个长度为n的序列A,下标从1至n。显然地,这个序列共有n(n+1)/2个子区间。对于任意一个子区间[l,r],如果该子区间内的众数在该子区间的出现次数严格大于(r?l+1)/2(即该子区间长度的一半),那么Yazid就说这个子区间是"新生舞会的"。所谓众数,即为该子区间内出现次数最多的数。特别地,如果出现次数最多的数有多个,我们规定值最小的数为众数。现在,Yazid想知道,共有多少个子区间是"新生舞会的"

Input

第一行2个用空格隔开的非负整数n,type,表示序列的长度和数据类型。数据类型的作用将在子任务中说明。
第二行n个用空格隔开的非负整数,依次为A1,A2,...,An,描述这个序列。
N<=500000,0<=Type<=3
对于所有数据,保证 0 ≤ Ai ≤ n ? 1。
对于 type = 0 的数据,没有任何特殊约定。
对于 type = 1 的数据,保证 Ai ∈ {0, 1}。
对于 type = 2 的数据,保证序列 A 的众数在整个序列中的出现次数不超过 15。
对于 type = 3 的数据,保证 Ai ≤ 7。

Output

输出一行一个整数,表示答案。

Sample Input

5 0
1 1 2 2 3

Sample Output

10
//"新生舞会的" 子区间有 [1, 1], [1, 2], [1, 3], [2, 2], [2, 4], [3, 3],
[3, 4], [3, 5], [4, 4], [5, 5]共 10 个。

题解:考虑枚举众数,我们用vector维护每种数的所有出现位置,然后我们将这个数的所有位置看成+1,其它位置看成-1,于是答案就变成了求多少区间的和>0。

我们考虑将所有连续的-1合并到一起,这样的话连续-1的个数就不会超过+1的个数+1了,然后枚举右端点。因为区间和可以看成前缀相减,所以我们用s[i]表示前缀和,那么我们要统计的就是左面有多少s[j]<s[i],自然想到用线段树来维护有多少个数的s值等于一个数。那么,对于一个+1,我们可以用简单的线段树区间求和搞定;对于一段-1,这段区间对答案的贡献就是$\sum\limits_{i=1}^{r-l+1}\sum\limits_{j=-\infty}^{s[l-1]-1-i}cnt[j]$(cnt表示有多少个数的s等于j)。发现这个东西可以用线段树维护cnt[i]和i*cnt[i]来实现,于是此题就做完了。

但是由于BZ太慢了,所以搞了若干个卡常小优化才过~

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define lson x<<1
#define rson x<<1|1
using namespace std;
const int maxn=500010;
typedef long long ll;
ll ans;
int n;
vector<int> p[maxn];
int s1[maxn<<3],z1[maxn<<3];
ll s2[maxn<<3],z2[maxn<<3];
int tag[maxn<<3];
bool clr[maxn<<3];
inline void pushdown(int x)
{
if(clr[x]) clr[lson]=clr[rson]=1,s1[lson]=s1[rson]=s2[lson]=s2[rson]=tag[lson]=tag[rson]=clr[x]=0;
if(tag[x]) s1[lson]+=z1[lson]*tag[x],s1[rson]+=z1[rson]*tag[x],s2[lson]+=z2[lson]*tag[x],s2[rson]+=z2[rson]*tag[x],tag[lson]+=tag[x],tag[rson]+=tag[x],tag[x]=0;
}
void build(int l,int r,int x)
{
if(l==r)
{
z1[x]=1,z2[x]=l;
return ;
}
int mid=(l+r)>>1;
build(l,mid,lson),build(mid+1,r,rson);
z1[x]=z1[lson]+z1[rson],z2[x]=z2[lson]+z2[rson];
}
void updata(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b)
{
s1[x]+=z1[x],s2[x]+=z2[x],tag[x]++;
return ;
}
pushdown(x);
int mid=(l+r)>>1;
if(a<=mid) updata(l,mid,lson,a,b);
if(b>mid) updata(mid+1,r,rson,a,b);
s1[x]=s1[lson]+s1[rson],s2[x]=s2[lson]+s2[rson];
}
int query1(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s1[x];
pushdown(x);
int mid=(l+r)>>1;
if(b<=mid) return query1(l,mid,lson,a,b);
if(a>mid) return query1(mid+1,r,rson,a,b);
return query1(l,mid,lson,a,b)+query1(mid+1,r,rson,a,b);
}
ll query2(int l,int r,int x,int a,int b)
{
if(a<=l&&r<=b) return s2[x];
pushdown(x);
int mid=(l+r)>>1;
if(b<=mid) return query2(l,mid,lson,a,b);
if(a>mid) return query2(mid+1,r,rson,a,b);
return query2(l,mid,lson,a,b)+query2(mid+1,r,rson,a,b);
}
inline char nc()
{
static char buf[100000],*p1=buf,*p2=buf;
return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
}
inline int rd()
{
int ret=0,f=1; char gc=nc();
while(!isdigit(gc)) {if(gc=='-') f=-f; gc=nc();}
while(isdigit(gc)) ret=ret*10+(gc^'0'),gc=nc();
return ret*f;
}
int main()
{
n=rd(),rd();
register int i,j,l,r,sum;
for(i=1;i<=n;i++) j=rd(),p[j].push_back(i);
build(-n,n,1);
for(i=0;i<n;i++) if(p[i].size())
{
s1[1]=s2[1]=tag[1]=sum=0,clr[1]=1;
p[i].push_back(n+1);
updata(-n,n,1,0,0);
for(j=0;j<(int)p[i].size();j++)
{
if((!j&&p[i][j]>1)||(j&&p[i][j]>p[i][j-1]+1))
{
l=(!j)?1:(p[i][j-1]+1),r=p[i][j]-1;
if(j) ans+=query1(-n,n,1,-n,sum-1)*(r-l+1)-query2(-n,n,1,sum-(r-l+1),sum-1)+query1(-n,n,1,sum-(r-l+1),sum-1)*(sum-1-(r-l+1));
updata(-n,n,1,sum-(r-l+1),sum-1);
sum-=(r-l+1);
}
if(j!=(int)p[i].size()-1) sum++,ans+=query1(-n,n,1,-n,sum-1),updata(-n,n,1,sum,sum);
}
}
printf("%lld",ans);
return 0;
}//5 0 1 1 0 1 1

【BZOJ5110】[CodePlus2017]Yazid 的新生舞会 线段树的更多相关文章

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

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

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

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

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

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

  4. 【bzoj5110】Yazid的新生舞会

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

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

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

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

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

  7. luogu P4062 [Code+#1]Yazid 的新生舞会(线段树+套路)

    今天原来是平安夜啊 感觉这题是道好题. 一个套路枚举权值\(x\),把权值等于\(x\)的设为1,不等于的设为-1,然后问题转化为多少个区间权值和大于. 发现并不是很好做,还有一个套路,用前缀和查分来 ...

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

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

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

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

随机推荐

  1. 修改Linux文件句柄限制

    1.  添加ulimit -HSn 655350   到/etc/profile 2. 配置生效  source /etc/profile 修改linux文件句柄数 分类: LINUX 2010-09 ...

  2. Arrays.sort和Collections.sort实现原理解析

    Arrays.sort和Collections.sort实现原理解析 1.使用 排序 2.原理 事实上Collections.sort方法底层就是调用的array.sort方法,而且不论是Collec ...

  3. 公司内网成功实现WSUS在不连外网的条件下更新补丁包!

    微软的WSUS的命令行很有帮助! 为了便于管理,WSUS服务器中提供了一个命令行工具WSUSUtil.exe,你可以使用它完成一些在WSUS管理控制台中不能进行的任务,例如导入导出数据等等.WSUSU ...

  4. Javascript中最常用的61个经典技巧[转]

    1. oncontextmenu="window.event.returnValue=false" 将彻底屏蔽鼠标右键<table border oncontextmenu= ...

  5. Qt中delete的问题

    最近项目遇到了一个bug,压力测试ui总会崩溃,gdb调试未果,跑到了库函数,无从查起: (gdb)bt #0 0x4146b1e4 in QWidgetPrivate::drawWidget(QPa ...

  6. BCM_SDK命令

    启动bcm的sdk,会进入一个类似shell的交互界面,在其中如入命令,可以配置交换机芯片.本文主要记录一下命令: 1.端口限速命令 2.链路聚合命令 3.i2c控制命令 启动方法: /tmp/bcm ...

  7. 多媒体开发之rtcp详解---rtcp数据包

    http://www.360doc.com/content/13/0606/10/1317564_290865866.shtml http://blog.csdn.net/hrbeuwhw/artic ...

  8. linux -- 服务开机自启动

    好吧,最近需要用到开机启动服务,百度了一下,几乎都是一个版本,然后之间各种传递.我也抄个 ******************************************************* ...

  9. python cython 模块(1)

    python 是一门动态类型的语音,其开发速度比C,C++等静态语言块, 但是速度慢很多, 而cython 通过混合C和python 的语法,可以提高python代码的运行速度 1) 安装cython ...

  10. linux上nginx上配置虚拟主机的相关配置

    1.配置主配置: nginx/conf/nginx.conf 2.虚拟主机配置:nginx/conf/extra/learn.weixin.com.conf 配置完后,重启服务器!