概述
链接
http://codeforces.com/contest/1005/problem/E2
题解
思路清奇
令
f(x)
f
(
x
)
表示中位数大于等于
x
x
且包含的区间个数,
y
y
表示这个数列里最小的比大的数,若
y
y
不存在,答案为,若
y
y
存在,答案为
先找到第一个
m
m
,指针指向这个位置,凡是左端点在这个
m
m
左侧,右端点在这个右侧(inclusive)的区间都是“包含
m
m
的区间”。
计算:
大于等于
x
x
的数我设为,小于
x
x
的数我设为,一个区间的和如果大于等于
1
1
,就肯定要被计入答案。前缀和一下,,
sl<sr
s
l
<
s
r
,我开一个值域
bit
b
i
t
,把
p
p
右侧(inclusive)的在其值对应的位置
+1
+
1
,然后扫描左侧,每次把
SUM−si
S
U
M
−
s
i
计入答案,其中
SUM
S
U
M
是整个
bit
b
i
t
的和。
然后移动
p
p
指向下一个,把两个
p
p
之间的这一段从
bit
b
i
t
里剔除,再统计这一段区域的答案
代码
#include <cstdio>
#include <algorithm>
#include <cstring>
#define ll long long
#define maxn 200010
#define mst(x) memset(x,0,sizeof(x))
#define lowbit(x) (x&-x)
using namespace std;
ll n, m, a[maxn], b[maxn], s[maxn], bit[maxn<<1], c[maxn<<1];
ll bitsum(ll pos)
{
ll ans=0;
for(;pos;pos-=lowbit(pos))ans+=bit[pos];
return ans;
}
void bitadd(ll pos, ll x){if(pos>0)for(;pos<=(n<<1);pos+=lowbit(pos))bit[pos]+=x;}
ll find_next(ll x)
{
for(x++;x<=n;x++)if(a[x]==m)return x;
return -1;
}
ll work(ll x)
{
ll p, i, ans=0, to;
mst(bit), mst(b), mst(s);
for(p=1;p<=n;p++)if(a[p]==m)break;
if(p>n)return 0;
for(i=1;i<=n;i++)if(a[i]>=x)b[i]=1; else b[i]=-1;
for(i=1;i<=n;i++)s[i]=s[i-1]+b[i];
for(i=p;i<=n;i++)bitadd(s[i]+n,1);
for(i=0;i<p;i++)ans+=bitsum(n<<1)-bitsum(s[i]+n);
for(to=find_next(p);to^-1;to=find_next(to))
{
for(i=p;i<to;i++)bitadd(s[i]+n,-1);
for(i=p;i<to;i++)ans+=bitsum(n<<1)-bitsum(s[i]+n);
p=to;
}
return ans;
}
ll read(ll x=0)
{
char c;
for(c=getchar();c<48 or c>57;c=getchar());
for(;c>=48 and c<=57;c=getchar())x=(x<<1)+(x<<3)+c-48;
return x;
}
int main()
{
ll i, y=0x3f3f3f3f, ans;
n=read(), m=read();
for(i=1;i<=n;i++)
{
a[i]=read();
if(a[i]>m)y=min(y,a[i]);
}
ans=work(m);
if(y^0x3f3f3f3f)ans-=work(y);
printf("%I64d",ans);
return 0;
}
最后
以上就是飞快绿草为你收集整理的Codeforces Round #496 (Div. 3) E2. Median on Segments (General Case Edition)链接题解代码的全部内容,希望文章能够帮你解决Codeforces Round #496 (Div. 3) E2. Median on Segments (General Case Edition)链接题解代码所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复