<?xml version='1.0' encoding='UTF-8'?><?xml-stylesheet href="http://www.blogger.com/styles/atom.css" type="text/css"?><feed xmlns='http://www.w3.org/2005/Atom' xmlns:openSearch='http://a9.com/-/spec/opensearchrss/1.0/' xmlns:georss='http://www.georss.org/georss' xmlns:gd='http://schemas.google.com/g/2005' xmlns:thr='http://purl.org/syndication/thread/1.0'><id>tag:blogger.com,1999:blog-7428334680131248805</id><updated>2011-11-28T08:41:49.817+08:00</updated><category term='计算几何'/><category term='树'/><category term='树形ST表'/><category term='扫描线'/><category term='二分答案'/><category term='平衡树'/><category term='动态规划'/><title type='text'>E478: Don't panic!</title><subtitle type='html'>:help!</subtitle><link rel='http://schemas.google.com/g/2005#feed' type='application/atom+xml' href='http://e478.blogspot.com/feeds/posts/default'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7428334680131248805/posts/default?max-results=100'/><link rel='alternate' type='text/html' href='http://e478.blogspot.com/'/><link rel='hub' href='http://pubsubhubbub.appspot.com/'/><author><name>E478</name><uri>http://www.blogger.com/profile/07308113917123948245</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_76BFMNBlyRo/TPeMCRPyNiI/AAAAAAAAAFg/TApDpHyqlJ4/S220/face.png'/></author><generator version='7.00' uri='http://www.blogger.com'>Blogger</generator><openSearch:totalResults>2</openSearch:totalResults><openSearch:startIndex>1</openSearch:startIndex><openSearch:itemsPerPage>100</openSearch:itemsPerPage><entry><id>tag:blogger.com,1999:blog-7428334680131248805.post-3085102452035732984</id><published>2011-09-03T20:10:00.000+08:00</published><updated>2011-09-03T22:55:50.199+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='树'/><category scheme='http://www.blogger.com/atom/ns#' term='动态规划'/><category scheme='http://www.blogger.com/atom/ns#' term='树形ST表'/><title type='text'>ACM2011大连区域赛网络预选赛 H-1008 Parent and son</title><content type='html'>今天去大连区域赛的网络预选赛打了一次酱油，结果被虐翻了……才6题，罚时也巨高，原本应该能够更好的……&lt;br /&gt;&lt;br /&gt;H题，一棵&lt;i&gt;N&lt;/i&gt;个结点的树，结点从1~&lt;i&gt;N&lt;/i&gt;编号。然后有&lt;i&gt;M&lt;/i&gt;次询问，每次询问是两个数&lt;i&gt;i&lt;/i&gt;, &lt;i&gt;j&lt;/i&gt;，表示以&lt;i&gt;i&lt;/i&gt;为根结点，求&lt;i&gt;j&lt;/i&gt;的所有儿子中编号最小的结点（&lt;i&gt;F&lt;/i&gt;值）以及&lt;i&gt;j&lt;/i&gt;的所有子孙中编号最小的结点（&lt;i&gt;G&lt;/i&gt;值），如果&lt;i&gt;j&lt;/i&gt;是叶子结点则输出"no answers!"。&lt;br /&gt;&lt;br /&gt;这个题其实也不是很难，但是很麻烦很恶心，首先我们先任意建树（即任选一个结点为根），我们称之为原树。可以发现若&lt;i&gt;i&lt;/i&gt;不是&lt;i&gt;j&lt;/i&gt;的子孙，那么&lt;i&gt;j&lt;/i&gt;的子孙就是原树中的子孙；然而，若&lt;i&gt;i&lt;/i&gt;是&lt;i&gt;j&lt;/i&gt;的子孙，则有些麻烦：设从&lt;i&gt;j&lt;/i&gt;走到&lt;i&gt;i&lt;/i&gt;必须经过&lt;i&gt;j&lt;/i&gt;的某个儿子&lt;i&gt;k&lt;/i&gt;，首先在原树中不是&lt;i&gt;j&lt;/i&gt;的子孙的结点在新树中都变成了&lt;i&gt;j&lt;/i&gt;的子孙（不包括&lt;i&gt;j&lt;/i&gt;本身），其次&lt;i&gt;j&lt;/i&gt;的子孙还包括&lt;i&gt;j&lt;/i&gt;在原树中除了&lt;i&gt;k&lt;/i&gt;以外的其它儿子及其子孙结点。&lt;br /&gt;&lt;br /&gt;现在问题已经很明朗了，首先我们对于每个结点，维护4个域：&lt;i&gt;up&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;, &lt;i&gt;down&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;, &lt;i&gt;left&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;, &lt;i&gt;right&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;，其中&lt;i&gt;up&lt;/i&gt;表示（在原树中）不是&lt;i&gt;i&lt;/i&gt;的子孙结点，&lt;i&gt;down&lt;/i&gt;表示&lt;i&gt;i&lt;/i&gt;的子孙结点，&lt;i&gt;left&lt;/i&gt;, &lt;i&gt;right&lt;/i&gt;分别表示&lt;i&gt;i&lt;/i&gt;的左边和右边的所有兄弟结点，每个域都记录了&lt;i&gt;F&lt;/i&gt;值和&lt;i&gt;G&lt;/i&gt;值。我们需要做两遍深搜来求出所有的域值：第一遍求出&lt;i&gt;down&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;, &lt;i&gt;left&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;和&lt;i&gt;right&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;，然后第二遍可用&lt;i&gt;left&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;, &lt;i&gt;right&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;和&lt;i&gt;up&lt;sub&gt;i'&lt;/sub&gt;&lt;/i&gt;求出&lt;i&gt;up&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;，其中&lt;i&gt;i'&lt;/i&gt;为&lt;i&gt;i&lt;/i&gt;的父亲结点。那么对于第一种情况，答案就是&lt;i&gt;down&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;；对于第二种，首先求出&lt;i&gt;k&lt;/i&gt;，然后答案即可从&lt;i&gt;left&lt;sub&gt;k&lt;/sub&gt;&lt;/i&gt;, &lt;i&gt;right&lt;sub&gt;k&lt;/sub&gt;&lt;/i&gt;和&lt;i&gt;up&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;中取最小值得到。&lt;br /&gt;&lt;br /&gt;在深搜的过程中，我们对于每个结点，在其入栈和出栈时分别打上一个时间戳，那么每个结点可以用一个区间来表示，&lt;i&gt;j&lt;/i&gt;是&lt;i&gt;i&lt;/i&gt;的祖先当且仅当&lt;i&gt;j&lt;/i&gt;的区间包含了&lt;i&gt;i&lt;/i&gt;的区间。那么怎么求出&lt;i&gt;k&lt;/i&gt;点呢？对此我的做法是这样的：首先在深搜时求出每个结点的深度&lt;i&gt;dep&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt;，那么显然&lt;i&gt;k&lt;/i&gt;点就是&lt;i&gt;i&lt;/i&gt;点往上走&lt;i&gt;dep&lt;sub&gt;i&lt;/sub&gt;&lt;/i&gt; - &lt;i&gt;dep&lt;sub&gt;j&lt;/sub&gt;&lt;/i&gt; - 1步。我们建立一个树形ST表，用&lt;i&gt;F&lt;/i&gt;&lt;sub&gt;&lt;i&gt;i&lt;/i&gt;,&lt;i&gt;j&lt;/i&gt;&lt;/sub&gt;表示结点&lt;i&gt;i&lt;/i&gt;往上走2&lt;sup&gt;&lt;i&gt;j&lt;/i&gt;&lt;/sup&gt;步所到达的结点是哪个，然后显然我们可以在对数级别的时间内实现结点&lt;i&gt;i&lt;/i&gt;往上走任意步了。不过这种实现把我的整个算法拉到了(&lt;i&gt;N&lt;/i&gt;&amp;nbsp;+ &lt;i&gt;M&lt;/i&gt;)log&lt;i&gt;N&lt;/i&gt;的级别，不知道有没有更好的方法。&lt;br /&gt;&lt;br /&gt;至此本题已经得到解决。&lt;br /&gt;&lt;br /&gt;代码：（过几天放出）&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7428334680131248805-3085102452035732984?l=e478.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://e478.blogspot.com/feeds/3085102452035732984/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://e478.blogspot.com/2011/09/acm2011-dalian-regional-preliminary.html#comment-form' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7428334680131248805/posts/default/3085102452035732984'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7428334680131248805/posts/default/3085102452035732984'/><link rel='alternate' type='text/html' href='http://e478.blogspot.com/2011/09/acm2011-dalian-regional-preliminary.html' title='ACM2011大连区域赛网络预选赛 H-1008 Parent and son'/><author><name>E478</name><uri>http://www.blogger.com/profile/07308113917123948245</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_76BFMNBlyRo/TPeMCRPyNiI/AAAAAAAAAFg/TApDpHyqlJ4/S220/face.png'/></author><thr:total>0</thr:total></entry><entry><id>tag:blogger.com,1999:blog-7428334680131248805.post-4974995808323324462</id><published>2010-12-01T14:24:00.005+08:00</published><updated>2011-09-03T19:14:40.436+08:00</updated><category scheme='http://www.blogger.com/atom/ns#' term='扫描线'/><category scheme='http://www.blogger.com/atom/ns#' term='平衡树'/><category scheme='http://www.blogger.com/atom/ns#' term='二分答案'/><category scheme='http://www.blogger.com/atom/ns#' term='计算几何'/><title type='text'>最近圆对</title><content type='html'>最近圆对是一个非常经典的计算几何问题，其大意为：给出&lt;i&gt;N&lt;/i&gt;个两两不相交的圆，求相距最近的两个圆的距离。&lt;br /&gt;&lt;br /&gt;我们先二分答案，将问题转换为判定性问题：判断能否找到距离≤&lt;i&gt;a&lt;/i&gt;的一对圆。如果将每个圆的半径都增加&lt;i&gt;a&lt;/i&gt;/2， 那么实际上该问题就是判断是否有两圆相交（或者相切）。判断圆相交可以采用扫描线+平衡树的方法来实现。&lt;br /&gt;&lt;br /&gt;对于每个圆(&lt;i&gt;x&lt;/i&gt;, &lt;i&gt;y&lt;/i&gt;, &lt;i&gt;r&lt;/i&gt;)，有两个关键点：左边界和右边界，即&lt;i&gt;x&lt;/i&gt;-&lt;i&gt;r&lt;/i&gt;和&lt;i&gt;x&lt;/i&gt;+&lt;i&gt;r&lt;/i&gt;。首先我们对所有关键点进行排序，然后维护一颗以圆的&lt;i&gt;y&lt;/i&gt;坐标为关键字的平衡树，对于每个关键点，如果它是左界，则将相对应的圆插入至平衡树，若为右界则做删除操作。我们只需在每次插入和删除操作时（设操作结点为&lt;i&gt;i&lt;/i&gt;），判断&lt;i&gt;i&lt;/i&gt;、&lt;i&gt;i&lt;/i&gt;的前趋、&lt;i&gt;i&lt;/i&gt;的后继这三个圆是否两两不相交。若出现相交，则说明答案≤&lt;i&gt;a&lt;/i&gt;&lt;i&gt;&lt;/i&gt;（能找到距离≤&lt;i&gt;a&lt;/i&gt;的一对圆），否则答案&amp;gt;&lt;i&gt;a&lt;/i&gt;。&lt;br /&gt;&lt;br /&gt;该算法的时间复杂度为&lt;i&gt;O&lt;/i&gt;(&lt;i&gt;N&lt;/i&gt;log&lt;i&gt;N&lt;/i&gt;log&lt;i&gt;R&lt;/i&gt;)，其中&lt;i&gt;R&lt;/i&gt;为答案的范围。&lt;br /&gt;&lt;br /&gt;顺便提一句：如果圆的半径全部相等，则该题有复杂度更低的&lt;i&gt;O&lt;/i&gt;(&lt;i&gt;N&lt;/i&gt;log&lt;i&gt;N&lt;/i&gt;)的做法：最近点对。&lt;br /&gt;&lt;br /&gt;代码：&lt;a name='more'&gt;&lt;/a&gt;&lt;pre class="prettyprint linenums"&gt;#include &amp;lt;algorithm&amp;gt;&lt;br /&gt;#include &amp;lt;set&amp;gt;&lt;br /&gt;#include &amp;lt;stdio.h&amp;gt;&lt;br /&gt;using namespace std;&lt;br /&gt;&lt;br /&gt;const double ZERO = 1e-8;&lt;br /&gt;&lt;br /&gt;struct Circle {&lt;br /&gt;    double x, y, r;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;struct Point {&lt;br /&gt;    double x;&lt;br /&gt;    bool in;&lt;br /&gt;    long i;&lt;br /&gt;};&lt;br /&gt;&lt;br /&gt;Circle a[50000];&lt;br /&gt;Point b[100000];&lt;br /&gt;set&amp;lt;Circle&amp;gt; f;&lt;br /&gt;set&amp;lt;Circle&amp;gt;::iterator s1, s2, s3;&lt;br /&gt;long n, m;&lt;br /&gt;&lt;br /&gt;Circle tmp;&lt;br /&gt;long i;&lt;br /&gt;double l = 0, r = 1e6, mid;&lt;br /&gt;&lt;br /&gt;inline bool is_zero(const double x) {&lt;br /&gt;    return -ZERO &amp;lt;= x &amp;amp;&amp;amp; x &amp;lt;= ZERO;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;inline bool cmp_point(const Point &amp;amp;a, const Point &amp;amp;b) {&lt;br /&gt;    return a.x &amp;lt; b.x;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;inline bool operator &amp;lt;(const Circle &amp;amp;a, const Circle &amp;amp;b) {&lt;br /&gt;    return is_zero(a.y - b.y) ? a.x &amp;lt; b.x : a.y &amp;lt; b.y;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;inline double sqr(const double x) {&lt;br /&gt;    return x * x;&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;inline bool collide(const Circle &amp;amp;a, const Circle &amp;amp;b) {&lt;br /&gt;    return sqr(a.x - b.x) + sqr(a.y - b.y) &amp;lt; sqr(a.r + mid + b.r + mid);&lt;br /&gt;}&lt;br /&gt;&lt;br /&gt;int main() {&lt;br /&gt;    scanf("%ld", &amp;amp;n);&lt;br /&gt;    for (i = 0; i &amp;lt; n; ++i) scanf("%lf%lf%lf", &amp;amp;a[i].x, &amp;amp;a[i].y, &amp;amp;a[i].r);&lt;br /&gt;&lt;br /&gt;    /*int j;double min=1e10,tp;&lt;br /&gt;    for (i=0;i&amp;lt;n;++i)&lt;br /&gt;        for (j=i+1;j&amp;lt;n; ++j) {&lt;br /&gt;            tp=sqrt(sqr(a[i].x-a[j].x)+sqr(a[i].y-a[j].y))-a[i].r-a[j].r;&lt;br /&gt;            if (min&amp;gt;tp)min=tp;&lt;br /&gt;        }&lt;br /&gt;    printf("%.6lf\n",min);&lt;br /&gt;    */&lt;br /&gt;    while (r - l &amp;gt; ZERO) {&lt;br /&gt;        mid = (l + r) * .5;&lt;br /&gt;        for (m = 0, i = 0; i &amp;lt; n; ++i) {&lt;br /&gt;            b[m].x = a[i].x - a[i].r - mid;&lt;br /&gt;            b[m].in = true, b[m++].i = i;&lt;br /&gt;            b[m].x = a[i].x + a[i].r + mid;&lt;br /&gt;            b[m].in = false, b[m++].i = i;&lt;br /&gt;        }&lt;br /&gt;        sort(b, b + m, cmp_point);&lt;br /&gt;&lt;br /&gt;        f.clear();&lt;br /&gt;        tmp.x = tmp.y = -1e30, tmp.r = 0, f.insert(tmp);&lt;br /&gt;        tmp.x = tmp.y = 1e30, f.insert(tmp);&lt;br /&gt;        for (i = 0; i &amp;lt; m; ++i)&lt;br /&gt;            if (b[i].in) {&lt;br /&gt;                s1 = s2 = s3 = f.insert(a[b[i].i]).first;&lt;br /&gt;                --s1, ++s3;&lt;br /&gt;                if (collide(*s1, *s2) || collide(*s2, *s3) || collide(*s3, *s1)) break;&lt;br /&gt;            } else {&lt;br /&gt;                s1 = s2 = s3 = f.find(a[b[i].i]);&lt;br /&gt;                --s1, ++s3;&lt;br /&gt;                if (collide(*s1, *s2) || collide(*s2, *s3) || collide(*s3, *s1)) break;&lt;br /&gt;                f.erase(s2);&lt;br /&gt;            }&lt;br /&gt;        i &amp;lt; m ? r = mid : l = mid;&lt;br /&gt;    }&lt;br /&gt;&lt;br /&gt;    printf("%.6lf", l * 2);&lt;br /&gt;    return 0;&lt;br /&gt;}&lt;/pre&gt;&lt;div class="blogger-post-footer"&gt;&lt;img width='1' height='1' src='https://blogger.googleusercontent.com/tracker/7428334680131248805-4974995808323324462?l=e478.blogspot.com' alt='' /&gt;&lt;/div&gt;</content><link rel='replies' type='application/atom+xml' href='http://e478.blogspot.com/feeds/4974995808323324462/comments/default' title='帖子评论'/><link rel='replies' type='text/html' href='http://e478.blogspot.com/2010/12/closest-circle.html#comment-form' title='0 条评论'/><link rel='edit' type='application/atom+xml' href='http://www.blogger.com/feeds/7428334680131248805/posts/default/4974995808323324462'/><link rel='self' type='application/atom+xml' href='http://www.blogger.com/feeds/7428334680131248805/posts/default/4974995808323324462'/><link rel='alternate' type='text/html' href='http://e478.blogspot.com/2010/12/closest-circle.html' title='最近圆对'/><author><name>E478</name><uri>http://www.blogger.com/profile/07308113917123948245</uri><email>noreply@blogger.com</email><gd:image rel='http://schemas.google.com/g/2005#thumbnail' width='32' height='32' src='http://1.bp.blogspot.com/_76BFMNBlyRo/TPeMCRPyNiI/AAAAAAAAAFg/TApDpHyqlJ4/S220/face.png'/></author><thr:total>0</thr:total></entry></feed>
