1. 程式人生 > >SHOI 2013 【扇形面積並】

SHOI 2013 【扇形面積並】

早上考的,我打了80分的部分分,出來和同學討論的時候真想扇自己一巴掌。。。。。。

題目描述:

  

  給定 n 個同心的扇形,求有多少面積,被至少k 個扇形所覆蓋。

輸入輸出格式

輸入格式:

第一行是三個整數 n,m,k。n 代表同心扇形個數,m代表將(−π ,π ]的角度區間平均分成2m 份。

從第二行開始的 n 行,每行三個整數r,a1,a2。描述了一個圓心在原點的扇形,半徑為r,圓心角是從弧度π*a1/mπa1/m到π*a2/mπa2/m(a1 不一定小於 a2)。

  輸出格式:

       輸出一個整數 ans ,π/2m*ansπ/2mans等於至少k 個扇形所覆蓋的總面積。

資料保證答案在2^{63} - 12631範圍內。

思路分析:

嗯,好,讓我們先來看看部分分做法。

30分:

  大暴力,就不講了吧。

60分:

  差分,因為所有半徑都是一樣的,所以我們只需要求出所有被覆蓋過大於等於k次的段就可以了。

80分:

  寫一棵權值線段樹,在順便用一下差分思想(在起始的地方把半徑加入權值線段樹,在終止的時候把半徑的地方-1就好了,然後每次查詢最大值)。

100分:

  嗯,在講100分演算法前先讓我扇自己一巴掌。。。。。。

  其實你們在看80分演算法的時候應該心裡都在嘀咕:這不是把求最大改成求第k大不就是正解了嘛?嗯,沒錯,就是這樣。

  我考場腦抽了竟然沒想到,啊啊啊啊啊啊啊啊啊啊啊啊!!!!!!!!!!!!!!!!!!!

程式碼實現:

var
    next_insert,val_insert,next_delete,val_delete:array[1..4000000]of longint;
    head_insert,head_delete:array[-1000000..1000000]of longint;
    cnt:array[-1000000..1000000]of longint;
    a:array[1..2000000]of longint;
    tot,tot_insert,tot_delete,v:longint;
    ans,x,y,n,m,need,s,t,r:int64;
    i,j:longint;
procedure add_insert(x,v:longint); begin inc(tot_insert); next_insert[tot_insert]:=head_insert[x]; head_insert[x]:=tot_insert; val_insert[tot_insert]:=v; end; procedure add_delete(x,v:longint); begin inc(tot_delete); next_delete[tot_delete]:=head_delete[x]; head_delete[x]:=tot_delete; val_delete[tot_delete]:=v; end; procedure add(s,t,r:int64); begin if s=t then exit; inc(cnt[s]); add_insert(s,r); dec(cnt[t]); add_delete(t,r); end; procedure update(k,l,r,x,z:longint); var mid:longint; begin a[k]:=a[k]+z; if l=r then exit; mid:=(l+r)>>1; if x<=mid then update(k*2,l,mid,x,z) else update(k*2+1,mid+1,r,x,z); end; function query(k,l,r,need:longint):longint; var mid:longint; begin if l=r then exit(l); mid:=(l+r)>>1; if a[k*2+1]>=need then exit(query(k*2+1,mid+1,r,need)) else exit(query(k*2,l,mid,need-a[k*2+1])); end; begin read(n,m,need); for i:=1 to n do begin read(r,s,t);  
        //是不是覺得這個讀入處理很噁心,嗯,我也這麼覺得。。。。。。(當我看到a1不一定小於a2時,我真想提著西瓜刀去找出題人拼命)
if (s>=0)and(t>=0) then begin if s<t then add(s,t,r) else begin add(s,m,r); add(-m,0,r); add(0,t,r); end; end else if (s<0)and(t<0) then begin if s<t then add(s,t,r) else begin add(-m,t,r); add(0,m,r); add(s,0,r); end; end else if (s>=0)and(t<0) then begin add(s,m,r); add(-m,t,r); end else if (s<0)and(t>=0) then begin add(0,t,r); add(s,0,r); end; end; for i:=-m to m-1 do begin j:=head_insert[i]; while j>0 do begin v:=val_insert[j]; update(1,0,100000,v,1); j:=next_insert[j]; end; j:=head_delete[i]; while j>0 do begin v:=val_delete[j]; update(1,0,100000,v,-1); j:=next_delete[j]; end; x:=x+cnt[i]; if x>=need then begin y:=query(1,0,100000,need); ans:=ans+sqr(y); end; end; writeln(ans); end.