[题目描述]
在X的非负轴上有N个不在同一位置上的数,0或1.至少有1个0.
可以先任意把0染成1.
区间长度定义为,[L,R]中最右和最左的数的差的绝对值.
求一个最长区间,满足区间中所有数0和1的个数相同.
输出这个最长区间的长度.
一看到这道题就想到毛嘉怡那道很漂亮的前缀和应用。。
所以觉得是前缀和。。
对于每一个白牛,+1,对于每一个黑牛,-1。
这样我们只要寻找一个i,j使d[i]<=d[j] && (j-i) mod 2=0 && j-i最大。
想了想想出了一个很鬼畜的做法。。
我们枚举i,然后找到d[j]>=d[i]的最大j,可以使用RMQ来搞。。
为了满足(j-i) mod 2=0,两位一压压两次,第一次压奇数,第二次压偶数。。
觉得至少要200行+,所以很弃疗地看了yyl大神的题解。。
他的想法是这样:先建一棵线段树,线段树里的下标代表是前缀和的值,线段树里维护的东西是这个前缀和区间里最大的pos。
可能有点讲不清楚,就是说比如[1..4]这个节点的data是9,就代表满足1<=d[i]<=4的i最大是9;
从右向左扫描,扫到i的时候,为了查询一个d[j]>=d[i]的最大j,在(d[i],+maxlongint)中查找一个最大值,然后再把这个值插入。
为了满足(j-i) mod 2=0,建两棵线段树。
我觉得这里最巧妙的是打破了原来的常规,把线段树倒了过来。
比如对于一个数组i,d[i]。
正常的线段树是把i当做下标,d[i]当做节点里的值。
这个线段树是把d[i]当做下表,i当做节点里的值。
Code:
const shuru='fairphoto.in';
shuchu='fairphoto.out';
maxn=100001;
INF=1 shl 28;
type node=record
left,right,data:longint;
end;
var f,a,color:array[0..maxn] of longint;
t,ans,i,j,k,n:longint;
tree:array[0..1] of array[0..maxn*6] of node;
ch:char;
procedure init;
begin
readln(n);
for i:=1 to n do
begin
read(a[i]); read(ch); read(ch);
if ch='W' then color[i]:=1
else color[i]:=-1;
end;
end;
procedure qsort(left,right:longint);
var i,j,mid:longint;
begin
i:=left; j:=right; mid:=a[(i+j) shr 1];
repeat
while a[i]<mid do inc(i);
while a[j]>mid do dec(j);
if i<=j then begin
t:=a[i]; a[i]:=a[j]; a[j]:=t;
t:=color[i]; color[i]:=color[j]; color[j]:=t;
inc(i); dec(j);
end;
until i>j;
if j>left then qsort(left,j);
if i<right then qsort(i,right);
end;
procedure build(x,l,r:longint);
var mid:longint;
begin
tree[1][x].left:=l; tree[1][x].right:=r;
tree[0][x].left:=l; tree[0][x].right:=r;
if r>l then begin
mid:=(l+r) shr 1;
build(x shl 1,l,mid);
build(x shl 1+1,mid+1,r);
end;
end;
function max(a,b:longint):longint;
begin
if a>b then exit(a);
exit(b);
end;
procedure forever(sign,x,k,m:longint);
var mid:longint;
begin
if tree[sign][x].left=tree[sign][x].right then begin
tree[sign][x].data:=max(tree[sign][x].data,m);
exit;
end;
mid:=(tree[sign][x].left+tree[sign][x].right) shr 1;
if k<=mid then forever(sign,x shl 1,k,m)
else forever(sign,x shl 1+1,k,m);
tree[sign][x].data:=max(tree[sign][x shl 1].data,tree[sign][x shl 1+1].data);
end;
function ever(sign,x,l,r:longint):longint;
var mid:longint;
begin
ever:=0;
if (l<=tree[sign][x].left) and (r>=tree[sign][x].right) then exit(tree[sign][x].data);
mid:=(tree[sign][x].left+tree[sign][x].right) shr 1;
if l<=mid then ever:=ever(sign,x shl 1,l,r);
if r>mid then ever:=max(ever,ever(sign,x shl 1+1,l,r));
end;
procedure main;
begin
init;
qsort(1,n);
build(1,1,2*n+1);
for i:=1 to n do f[i]:=f[i-1]+color[i];
for i:=n downto 1 do
begin
ans:=max(ans,ever(i and 1,1,f[i]+n+1,n shl 1+1)-a[i+1]);
forever(i and 1,1,f[i]+n+1,a[i]);
end;
ans:=max(ans,ever(0,1,n+1,n shl 1+1)-a[1]);
writeln(ans);
end;
begin
main;
end.
extra
lsdsjy:"此题大概是NOIP T2难度"
妈蛋是vijos noip模拟赛T2难度么。。