51nod1962區間計數

2022-05-31 03:33:18 字數 3521 閱讀 2216

考慮每個值作為最大值的區間實際上可以用單調棧求出來,即找到左邊第乙個比它大的數l[i],右邊第乙個比它大的r[i],那就是左端點在[l[i],i]右端點在[i,r[i]]的區間是以第i個數作為最大值。

用乙個掃瞄線去做,維護當前線上矩形交的長度now。具體是這樣的:開2n個線段樹,對於每一種最大值開線段樹,分別用roota[i]和rootb[i]維護a和b的最大值為i的矩形在當前掃瞄線上覆蓋情況。每次乙個值為w的a產生的左上角[x1,y1],右下角[x2,y2]的矩形在x1處加入,now+=rootb[w]在[y1,y2]覆蓋了多少,再在roota[w]的線段樹修改。刪除把+改成-就行了。這樣最後ans+=now。

寫著非常簡單。

1

program

j01;

2const maxn=350086;3

var a,b:array[0..maxn]of

longint;

4 roota,rootb:array[0..maxn]of

longint;

5 la,lb:array[0..maxn]of

longint;

6 sta,stb:array[0..maxn]of

longint;

7 f:array[0..40*maxn]of

record l,r,tag,w:longint; end;8

topa,topb,cnt,n,i:longint;

9ll,rr,dd:longint;

10sum,now:int64;

1112

function min(a,b:longint):longint;inline;begin

if athen exit(a) else exit(b); end;13

function max(a,b:longint):longint;inline;begin

if a>b then exit(a) else exit(b); end;14

15function

ask(i,l,r:longint):longint;

16var

mid,res:longint;

17begin

18if i=0

then exit(0

);19

if(ll<=l)and(r<=rr)then

exit(f[i].w);

20 mid:=(l+r)div

2;res:=f[i].tag*(min(rr,r)-max(ll,l)+1

);21

if ll<=mid then res:=res+ask(f[i].l,l,mid);

22if mid+1

<=rr then res:=res+ask(f[i].r,mid+1

,r);

23exit(res);

24end;25

26procedure change(var

i:longint;l,r:longint);

27var

mid:longint;

28begin

29if i=0

then

30begin

31 inc(cnt);i:=cnt;

32end;33

if(ll<=l)and(r<=rr)then

34begin

35 inc(f[i].tag,dd);inc(f[i].w,dd*(r-l+1

));exit;

36end

;37 mid:=(l+r)div2;

38if ll<=mid then

change(f[i].l,l,mid);

39if mid+1

<=rr then change(f[i].r,mid+1

,r);

40 f[i].w:=f[i].tag*(r-l+1)+f[f[i].l].w+f[f[i].r].w;

41end;42

43begin

44readln(n);

45for i:=1

to n do

read(a[i]);

46for i:=1

to n do

read(b[i]);

47 fillchar(la,sizeof(la),0);fillchar(lb,sizeof(lb),0

);48 fillchar(roota,sizeof(roota),0);fillchar(rootb,sizeof(rootb),0

);49 a[0]:=maxlongint;b[0]:=maxlongint;topa:=0;topb:=0;sta[0]:=0;stb[0]:=0

;50 sum:=0;now:=0;51

for i:=1

to n do

52begin

53while a[sta[topa]]<=a[i] do

54begin

55 ll:=la[sta[topa]];rr:=sta[topa];dd:=-1

;56 now:=now-ask(rootb[a[sta[topa]]],1

,n);

57 change(roota[a[sta[topa]]],1

,n);

58dec(topa);

59end;60

while b[stb[topb]]<=b[i] do

61begin

62 ll:=lb[stb[topb]];rr:=stb[topb];dd:=-1

;63 now:=now-ask(roota[b[stb[topb]]],1

,n);

64 change(rootb[b[stb[topb]]],1

,n);

65dec(topb);

66end

;67 la[i]:=sta[topa]+1;ll:=la[i];rr:=i;dd:=1

;68 now:=now+ask(rootb[a[i]],1,n);change(roota[a[i]],1

,n);

69 inc(topa);sta[topa]:=i;

70 lb[i]:=stb[topb]+1;ll:=lb[i];rr:=i;dd:=1

;71 now:=now+ask(roota[b[i]],1,n);change(rootb[b[i]],1

,n);

72 inc(topb);stb[topb]:=i;

73 sum:=sum+now;//writeln(now,'

',sum);

74end;75

writeln(sum);

76end.77

78

view code

51Nod1962 區間計數

兩個數列 請求出ans,ans定義如下 ans ni 1 nj i max max 注 內表示式為真,則為1,否則為0.1 n 3.5 1051 ai,bi n 樣例解釋 7個區間分別為 1,4 1,5 2,4 2,5 3,3 3,5 4,5 input 第一行乙個整數n 第二行n個整數ai 第三行...

51Nod1962 區間計數

這題與之前那道區間最值的題非常類似,依舊是二分區間,然後統計跨過中間點的區間貢獻。我們要選出小於等於和小於的,這樣就可以算出相等的區間長了。複雜度o nlogn by 大奕哥 1 include2 using namespace std 3 typedef long long ll 4 ll ans...

51nod 1712 區間求和

解法 這個題首先考慮乙個簡單情況 對於區間 x,y 權值為多少。容易寫出公式 f x y s y s x 1 sum y sum x 1 x 1 sum x 1 y x 1 其中s x 表示 從第乙個元素到第x個元素的 所有有序二元組的和 題目中定義的 sum表示字首和 這裡要求的是所有a x a ...