http://acmicpc.info/archives/1710
http://blog.renren.com/blog/271960376/918770698?bfrom=01020110200
https://gist.github.com/lychees/803f6e6a61c0f393660a
Problem D. Bathysphere
Brief description:
。。。x
轴上方给定一段折线。(一个分段线性可积函数)。
。。求 d
宽度的窗口内的最大面积。。。
Analysis:
Two Point
解方程
为了处理方便我们先准备一些辅助函数。。。
inline DB yy(int i, DB xx){ // 求横坐标为 xx 时的函数值。。 return y[i] + (xx-x[i])*slope[i]; } inline DB s(int i, DB st, DB ed){ //求 st 到 ed 这段区间的面积。。 return (ed-st)*(yy(i,st)+yy(i,ed)); }
考虑 Two Point
的部分。。我们用 ll
, rr
记录当前窗口的位置。。(rr-ll
总等于 d
。。。再用 l
, r
记录其左侧第一个结点的位置。。。
... for (;r<n-1;l+=ll==x[l+1],r+=rr==x[r+1]){ int d = min(x[r+1]-rr, x[l+1]-ll); DB a = slope[r]-slope[l], b = (yy(r,rr)-yy(l,ll))*2; if (sgn(a)){ DB dd = -b/(2*a); if (sgn(.0, dd) < 0 && sgn(dd, DB(d)) < 0){ checkMax(res, pre-(b*b/a/4)); } } checkMax(res, pre += s(r,rr,rr+d)-s(l,ll,ll+d)); ll+=d,rr+=d; } ...
。。就是每次我们取移动的步长 d
…。。
。。然后解这个窗口内二次方程。。看极值点是否落在步长范围之内。。
。。更新完之后。。再移动两个端点。。。
我们直接在移动端点的同时再尝试更新一次答案。。(因为有可能出现方程退化情况。。
const int N = int(2e5) + 9; int x[N], y[N], n; DB slope[N]; int D; inline DB yy(int i, DB xx){ return y[i] + (xx-x[i])*slope[i]; } inline DB s(int i, DB st, DB ed){ return (ed-st)*(yy(i,st)+yy(i,ed)); } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif Rush{ RD(n); RD(); REP(i, n) RD(x[i], y[i]); RD(D)*=2; REP(i, n-1) slope[i] = (DB)(y[i+1]-y[i])/(x[i+1]-x[i]); DB res = 0, pre = 0; int r; REP_N(r, n-1){ if (x[r+1] >= D) break; pre += s(r,x[r],x[r+1]); } checkMax(res, pre += s(r, x[r], D)); int l=0,ll=0,rr=D;r+=rr==x[r+1]; for (;r<n-1;l+=ll==x[l+1],r+=rr==x[r+1]){ int d = min(x[r+1]-rr, x[l+1]-ll); DB a = slope[r]-slope[l], b = (yy(r,rr)-yy(l,ll))*2; if (sgn(a)){ DB dd = -b/(2*a); if (sgn(.0, dd) < 0 && sgn(dd, DB(d)) < 0){ checkMax(res, pre-(b*b/a/4)); } } checkMax(res, pre += s(r,rr,rr+d)-s(l,ll,ll+d)); ll+=d,rr+=d; } OT(res/D/2); } }
Problem J. Tri-war
Brief description:
。。给定 $$n$$ 个结点的一棵树。。每次询问三个点 $$u_0, u_1, u_2$$。。。
。。。点 $$v$$ 被 $$u_x$$ 支配 。。如果 $$\forall y \not = x, d(u_x, v) < d(u_y, v) $$。。
。。。问这三个点所在的支配集的大小。。。
Analysis:
倍增祖先
LCA
分类讨论
两个点的情况:
。先铺好模板。。显然就是。。。。。(。Codeforces Round #140 和 SPOJ 1486. The Ants in a Tree
。。考虑 2 个点的。。设函数 up(u, k)
表示 $$u$$ 结点向上 $$k$$ 个位置的结点。。。
。。那么通过 倍增祖先
我们就可以将中点找到。。。之后根据路径的奇偶性讨论一下即可。。。
最后要么是。。。
u0 --- m --- u1
(这种情况存在着一些 灰色结点
。。(既不属于 $$u_0$$ 也不属于 $$u_1$$。。
要么是。。。
u0 --- m0 --- m1 --- u1
。。。复杂度 $$O(log(n))$$。。。(对于有边权的情况。。复杂度好像仍然是 $$O(log(n))$$ ?。。可以一边二分一边向上跳?)
。。。合理的使用 swap
以提高对讨论的抗性。。、、。。
(本题中 swap
的情况目测会茫茫多。。我们直接使用 ans[]
来记录答案。。)
void gao(int x, int y){ int z = lca(x,y), dx = dep[x]-dep[z], dy = dep[y]-dep[z], dd = dx+dy; int d = dd/2; if (d>=dx) swap(x, y), swap(dx, dy); int m = up(x,d); if (dd&1) ans[x] = sz[m], ans[y] = n-ans[x]; else ans[x] = sz[up(x,d-1)], ans[y] = d==dx?sz[up(y,d-1)]:n-sz[m]; }
三个点的情况:
。。。。现在讨论三个点的情况。。。
。。先按照 dep
对询问点排序。。
Case 1:链状
这种情况,$$u_0$$ 和 $$u_2$$ 都是它们各自对 $$u_1$$ 两个点时的答案。。。
。。。再把 $$u_1$$ 容斥出来。。。
void gao(int u0, int u1, int u2){ gao(u1, u2); int g = n-ans[u1]-ans[u2]; gao(u0, u1); ans[u1] -= ans[u2]+g; }
Case 2:叉状
我们求出三者的汇点 $$m$$。。并重新将询问的结点按照到 $$m$$ 的距离排序。。
m = entry(u0, u1, u2); SRT(I, cmp);
Case 2-1:$$m$$ 被其中一个结点支配
这种情况,$$u_1$$ 和 $$u_2$$ 都是它们各自对 $$u_0$$ 两个点时的答案。。。
。。。类似的。。再把 $$u_0$$ 容斥出来。。。
gao(u1, u0); int g1 = n-ans[u0]-ans[u1]; gao(u0, u2); int g2 = n-ans[u0]-ans[u2]; ans[u0] = n-ans[u1]-ans[u2]-g1-g2;
Case 2-2:$$m$$ 是灰色结点
这种情况还得分两种情况讨论。(恰好两个结点到 $$m$$ 距离相等,和三个结点到 $$m$$ 距离都相等。。)
。。但是处理起来恰好可以做到完全一样。。。。
最后注意 HDU
直接交会 dfs()
爆栈。。。
这里我使用了汇编调栈。。。。
const int N = int(1e5)+9, M = 2*N, LV = 18; int hd[N], suc[M], to[M]; int ST[LV+1][M], sz[N], fa[N][LV], st[N], dep[N]; int n, tt; inline bool elder(int a, int b){ return dep[a] < dep[b]; } inline int lca(int a, int b){ int l = st[a], r = st[b]; if (l > r) swap(l, r); ++r; int lv = lg2(r-l); return min(ST[lv][l], ST[lv][r-(1<<lv)], elder); } bool isa(int u1, int u2){ return lca(u1, u2) == u1; } int entry(int x, int y, int w){ int xy = lca(x, y); if (!isa(xy, w)) return xy; int xw = lca(x, w); return xw != xy ? xw : lca(y, w); } inline int d(int x, int y){ return dep[x]+dep[y]-2*dep[lca(x,y)]; } inline int up(int x, int t){ for (int i=0;i<LV&&t;++i,t>>=1) if (t&1) x = fa[x][i]; return x; } #define aa to[i^1] #define bb to[i] #define v bb void dfs(int u = 1){ ST[0][st[u] = ++tt] = u, sz[u] = 1; REP_G(i, u) if (!st[v]){ dep[v] = dep[u] + 1, fa[v][0] = u; FOR(lv, 1, LV) fa[v][lv] = fa[fa[v][lv-1]][lv-1]; dfs(v), ST[0][++tt] = u, sz[u] += sz[v]; } } #undef v int ans[N], m; bool cmp(int a, int b){ return d(a, m) < d(b, m); } void gao(int x, int y){ int z = lca(x,y), dx = dep[x]-dep[z], dy = dep[y]-dep[z], dd = dx+dy; int d = dd/2; if (d>=dx) swap(x, y), swap(dx, dy); int m = up(x,d); if (dd&1) ans[x] = sz[m], ans[y] = n-ans[x]; else ans[x] = sz[up(x,d-1)], ans[y] = d==dx?sz[up(y,d-1)]:n-sz[m]; } void gao(int u0, int u1, int u2){ gao(u1, u2); int g = n-ans[u1]-ans[u2]; gao(u0, u1); ans[u1] -= ans[u2]+g; } int main(){ #ifndef ONLINE_JUDGE freopen("in.txt", "r", stdin); //freopen("out.txt", "w", stdout); #endif int __size__ = 256 << 20; // 256MB char *__p__ = (char*)malloc(__size__) + __size__; __asm__("movl %0, %%esp\n" :: "r"(__p__)); Rush{ FOR_C(i, 2, RD(n)<<1){ RD(aa, bb); suc[i] = hd[aa], hd[aa] = i, ++i; suc[i] = hd[aa], hd[aa] = i; } dfs(); for ( int lv = 1 ; (1 << lv) <= tt ; lv ++ ){ for ( int i = 1 ; i + (1 << lv) <= tt + 1 ; i ++ ) ST[lv][i] = min(ST[lv-1][i], ST[lv-1][i + (1<<(lv-1))], elder); } Rush{ int u0, u1, u2; RD(u0, u1, u2); VI I; I.PB(u0), I.PB(u1), I.PB(u2); SRT(I, elder); #define u0 I[0] #define u1 I[1] #define u2 I[2] if (isa(u0, u1) && isa(u1, u2)){ gao(u0, u1, u2); // Case 1 } else{ m = entry(u0, u1, u2); SRT(I, cmp); if (d(u0,m) < d(u1,m)){ // Case 2.1 gao(u1, u0); int g1 = n-ans[u0]-ans[u1]; gao(u0, u2); int g2 = n-ans[u0]-ans[u2]; ans[u0] = n-ans[u1]-ans[u2]-g1-g2; } else{ // Case 2.2 gao(u0, u2), gao(u0, u1); } } #undef u0 #undef u1 #undef u2 printf("%d %d %d\n", ans[u0], ans[u1], ans[u2]); } fill(hd+1, hd+n+1, 0); fill(st+1, st+n+1, 0); tt = 0; } }