【題目描述】
在無聊的時候,小 $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只奶牛。接下來...