DTOJ 2768 圓圈遊戲(circle)

2022-08-26 02:03:10 字數 3070 閱讀 8388

【題目描述】

在無聊的時候,小 $k$ 和小 $h$ 會在紙上玩這樣乙個遊戲。

我們可以將紙看做乙個平面直角座標系。小 $h$ 會先在上面畫出 $n$ 個圓,並把每個圓的圓心以及半徑都告訴小 $k$。小 $h$ 畫的 $n$ 個圓中,任意兩個圓不會出現相交或相切的情況。小 $k$ 需要做的就是從這 $n$ 個圓中選出若干個圓,使得選出的任意乙個圓都不被另乙個選出的圓包含。遊戲的目標就是要選出盡量多的圓。

遊戲一次一次進行著,小 $k$ 已經對遊戲的規則感到了厭倦,所以他決定修改遊戲的規則。對於第 $i$ 個圓,我們定義它的價值為 $w_i$ 。新的遊戲目標是使得選出的圓價值和最大(不一定數量最多)。但是圓圈可能很多,或者圓圈的分布非常奇怪,或者小 $k$ 還有別的事情要做。所以他只好拜託你來幫他求出這個最大值了。

【輸入格式】

第一行乙個整數 $n$ 表示圓圈的個數。

接下來 $n$ 行每行 $4$ 個整數 $x_i,y_i,r_i$ 和 $w_i$ ,分別表示第 $i$ 個圓的圓心橫座標、縱座標、半徑,和價值。

【輸出格式】

輸出一行,包含乙個整數,代表選出的圓的最大價值。

【樣例】

樣例輸入

33 4 2 3

6 4 7 5

9 4 1 4

樣例輸出

7樣例解釋

如果選擇價值最大的圓 $2$ ,可以獲得的價值和為 $5$。如果選擇圓 $1$ 和圓 $3$,雖然它們的單個價值都不是最大的,但價值和可以達到 $3+ 4 = 7$。

【資料範圍與提示】

測試點編號

$n=$

$1$$1$

$2$$2$

$3$$3$

$4$$4$

$5$$8$

$6$$12$

$7$$16$

$8,9$

$1000$

$10,11$

$2000$

$12,13$

$3000$

$14,15$

$5000$

$16,17$

$60000$

$18,19$

$70000$

$20,21$

$80000$

$22,23$

$90000$

$24,25$

$100000$

對於全部測試資料 $1 \le x_i,y_i,r_i \le 10^8,1 \le w_i \le 1000 $。

保證不存在相交或相切的兩個圓。

【題解】

看到不互相包含的圓,顯然是最大權獨立集問題。又注意到每個圓一定被另乙個最小圓包含,因此圓與圓之間由包含關係構成樹形結構。若能夠建出樹則可以樹形 $dp$。

考慮 $60$ 分做法。按 $r$ 從小到大掃一遍,對於每個圓找到最小的包含它的圓,直接建邊跑樹形 $dp$ 即可。效率 $o(n^2)$。

考慮如何優化建樹。首先可以反過來建邊,從外往裡。同樣從小到大插入每個圓。由於圓與圓不相交,圓心在當前插入圓內的圓一定被當前圓包含。直接連邊然後刪除即可。

由於是二維限制,用 $kd-tree$ 或二維線段樹均可。

另一種做法是用掃瞄線,對於每個圓拆成上下兩半,左右兩個端點視為插入與刪除的掃瞄線。用 $set,splay$ 等資料結構維護每個半圓的位置上下關係。查詢時查詢上半圓前驅與下半圓後繼即可。

【**】

#includeinline int read ( void )

int f[100010],n,tot,root;

struct tree t[10000010];

struct circle c[100010];

std::vectore[100010];

const int inf=1000000000;

const int l=-inf,r=inf;

inline bool inside ( int l,int r,int d,int u,int x,int y,long long r )

inline void pushup ( int k )

inline int query ( int l,int r,int d,int u,int k,int x,int y,int r )

int mid1=(l+r)>>1,mid2=(d+u)>>1,res=0;

res+=query(l,mid1,d,mid2,t[k].ch[0],x,y,r);

res+=query(l,mid1,mid2+1,u,t[k].ch[1],x,y,r);

res+=query(mid1+1,r,d,mid2,t[k].ch[2],x,y,r);

res+=query(mid1+1,r,mid2+1,u,t[k].ch[3],x,y,r);

pushup(k);

return res;

}inline void modify ( int l,int r,int d,int u,int &k,int x,int y,int i )

int mid1=(l+r)>>1,mid2=(d+u)>>1;

if ( x<=mid1 and y<=mid2 ) modify(l,mid1,d,mid2,t[k].ch[0],x,y,i);

if ( x<=mid1 and y>mid2 ) modify(l,mid1,mid2+1,u,t[k].ch[1],x,y,i);

if ( x>mid1 and y<=mid2 ) modify(mid1+1,r,d,mid2,t[k].ch[2],x,y,i);

if ( x>mid1 and y>mid2 ) modify(mid1+1,r,mid2+1,u,t[k].ch[3],x,y,i);

pushup(k);

}signed main()

); for ( int i=1;i<=n;i++ ) f[i]=std::max(query(l,r,l,r,root,c[i].x,c[i].y,c[i].r),c[i].w),modify(l,r,l,r,root,c[i].x,c[i].y,i);

return !printf("%d\n",f[n]);

}

2768 圓圈遊戲(circle)

在無聊的時候,小k和小h會在紙上玩這樣乙個遊戲。我們可以將紙看做乙個平面直角座標系。小h會先在上面畫出 n nn 個圓,並把每個圓的圓心以及半徑都告訴小k。小h畫的 n nn 個圓中,任意兩個圓不會出現相交或相切的情況。小k需要做的就是從這 n nn 個圓中選出若干個圓,使得選出的任意乙個圓都不被另...

2768 圓圈遊戲(circle)

題目描述 在無聊的時候,小k和小h會在紙上玩這樣乙個遊戲。我們可以將紙看做乙個平面直角座標系。小h會先在上面畫出 n 個圓,並把每個圓的圓心以及半徑都告訴小k。小h畫的 n 個圓中,任意兩個圓不會出現相交或相切的情況。小k需要做的就是從這 n 個圓中選出若干個圓,使得選出的任意乙個圓都不被另乙個選出...

1 圓圈舞蹈(circle )

1 圓圈舞蹈 circle.問題描述 熊大媽的奶牛圍成了乙個圈在跳圓舞曲。由於沒有嚴格的教育,奶牛們之間的間隔距離不一致,現在告訴你相鄰兩個奶牛間的距離,熊大媽想知道兩隻最遠的奶牛到底隔了多遠。奶牛a到b的距離為a順時針走或逆時針走到達b的較短距離。輸入格式 第一行乙個整數n,表示有n只奶牛。接下來...