BZOJ2402 陶陶的难题II

orz mhy。看mhy的刷题记录成为了我成天的刷题方向了。

 

其实最初也没有想清楚。然后看了一眼mhy写的题解写了凸壳,秒懂。

 

二分一个答案,设它是ans。如果ans≥realAns的话,那么就会存在yi-ans*xi+qj-ans*pj≥0。然后i和j就分开了。于是变成了求一条路径上yi-ans*xi的最大值。把xi看作k,把yi看作b,就变成半平面交了。于是开归并式线段树把凸壳给记录下来就好了。然后复杂度大约是单次询问O(lg3(n))的?链剖后每棵树单独建树,然后复杂度我就不会算了TT。

 

于是就硬着头皮写了,然后发现跑得还挺快。

 

#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>

using namespace std;

const int maxn = 30009;
const int maxl = 15;
const int max_buf = maxn * maxl * 2;
const double eps = 1e-6;
const double finf = 1e10;

int ibuf_arr[max_buf], *ibuf(ibuf_arr);
double fbuf_arr[max_buf], *fbuf(fbuf_arr);

struct edge {
	int t;
	edge *next;
};

struct line {
	double k, b;
	inline double xCross(const line& a) {
		return (a. b - b) / (k - a. k);
	}
	inline double f(double x) {
		return k * x + b;
	}
};
line a[maxn << 1];

struct hull {
	int t;
	int *l;
	double *cx;
	void init(int x) {
		t = 1;
		l = ibuf ++;
		l[0] = x;
		cx = 0;
	}
	void merge(const hull& x, const hull& y) {
		static int stc[maxn];
		static double tx[maxn];
		t = 0;
		for (int i = 0, j = 0, c; i < x. t || j < y. t; ) {
			if (i == x. t || (j < y. t && a[x. l[i]]. k > a[y. l[j]]. k))
				c = y. l[j ++];
			else 
				c = x. l[i ++];
			if (t && fabs(a[c]. k - a[stc[t - 1]]. k) < eps) {
				if (a[c]. b >= a[stc[t - 1]]. b)
					-- t;
				else
					continue;
			}
			while (t > 1 && a[c]. xCross(a[stc[t - 2]]) <= tx[t - 2])
				-- t;
			if (t)
				tx[t - 1] = a[c]. xCross(a[stc[t - 1]]);
			stc[t ++] = c;
		}
		l = ibuf;
		ibuf += t;
		cx = fbuf;
		fbuf += t - 1;
		for (int i = 0; i < t; ++ i) {
			l[i] = stc[i];
			if (i < t - 1)
				cx[i] = a[stc[i]]. xCross(a[stc[i + 1]]);
		}
	}
	double qry(double x) {
		int p(lower_bound(cx, cx + t - 1, x) - cx);
		return a[l[p]]. f(x);
	}
};
struct seg {
	hull h[2];
	int l, r;
	seg *ls, *rs;
};

int n, m;
double qans[2], qx;
int fa[maxn], d[maxn], sz[maxn], tc, fc[maxn], ch[maxn], cl[maxn], *ci[maxn];
edge elst[maxn << 1], *ep(elst), *head[maxn];
seg slst[maxn << 2], *sp(slst), *rt[maxn];

inline void upMax(double& a, double b) {
	if (a < b)
		a = b;
}
inline void addEdge(int u, int v) {
	ep-> t = v;
	ep-> next = head[u];
	head[u] = ep ++;
}

#define cpos(_p_) (d[_p_]-d[ch[fc[_p_]]])
#define midp(p) ((p->l+p->r)>>1)

inline seg* sgtBuild(int l, int r, int* ci) {
	seg *p(sp ++);
	p-> l = l;
	p-> r = r;
	if (l + 1 == r) {
		p-> h[0]. init(ci[l]);
		p-> h[1]. init(ci[l] + n);
	}
	else {
		p-> ls = sgtBuild(l, midp(p), ci);
		p-> rs = sgtBuild(midp(p), r, ci);
		p-> h[0]. merge(p-> ls-> h[0], p-> rs-> h[0]);
		p-> h[1]. merge(p-> ls-> h[1], p-> rs-> h[1]);
	}
	return p;
}
inline void sgtQry(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r) {
		upMax(qans[0], p-> h[0]. qry(qx));
		upMax(qans[1], p-> h[1]. qry(qx));
	}
	else if (r <= midp(p))
		sgtQry(p-> ls, l, r);
	else if (l >= midp(p))
		sgtQry(p-> rs, l, r);
	else {
		sgtQry(p-> ls, l, midp(p));
		sgtQry(p-> rs, midp(p), r);
	}
}

void divide() {
	static int q[maxn];
	int hd(0), tl(1);
	memset(d, 0, sizeof(d));
	d[q[0] = 1] = 1;
	fa[1] = 0;
	while (hd < tl) {
		int p(q[hd ++]);
		for (edge* e = head[p]; e; e = e-> next)
			if (!d[e-> t]) {
				d[e-> t] = d[p] + 1;
				fa[e-> t] = p;
				q[tl ++] = e-> t;
			}
	}
	tc = 0;
	for (int i = tl - 1; i >= 0; -- i) {
		int p(q[i]), z(-1);
		sz[p] = 1;
		for (edge* e = head[p]; e; e = e-> next)
			if (fa[e-> t] == p) {
				sz[p] += sz[e-> t];
				if (z == -1 || sz[e-> t] > sz[z])
					z = e-> t;
			}
		if (z == -1)
			cl[fc[p] = ++ tc] = 1;
		else
			++ cl[fc[p] = fc[z]];
		ch[fc[p]] = p;
	}
	for (int i = 1; i <= tc; ++ i) {
		ci[i] = ibuf;
		ibuf += cl[i];
	}
	for (int i = 1; i <= n; ++ i)
		ci[fc[i]][cpos(i)] = i;
	for (int i = 1; i <= tc; ++ i)
		rt[i] = sgtBuild(0, cl[i], ci[i]);
}

bool check(int u, int v, double x) {
	qans[0] = qans[1] = -finf;
	qx = -x;
	while (fc[u] ^ fc[v])
		if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
			sgtQry(rt[fc[u]], 0, cpos(u) + 1);
			u = fa[ch[fc[u]]];
		}
		else {
			sgtQry(rt[fc[v]], 0, cpos(v) + 1);
			v = fa[ch[fc[v]]];
		}
	if (d[u] < d[v])
		sgtQry(rt[fc[u]], cpos(u), cpos(v) + 1);
	else
		sgtQry(rt[fc[u]], cpos(v), cpos(u) + 1);
	return qans[0] + qans[1] >= 0;
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif

	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i)
		scanf("%lf", &a[i]. k);
	for (int i = 1; i <= n; ++ i)
		scanf("%lf", &a[i]. b);
	for (int i = 1; i <= n; ++ i)
		scanf("%lf", &a[i + n]. k);
	for (int i = 1; i <= n; ++ i)
		scanf("%lf", &a[i + n]. b);
	memset(head, 0, sizeof(head));
	for (int i = 1; i < n; ++ i) {
		int u, v;
		scanf("%d%d", &u, &v);
		addEdge(u, v);
		addEdge(v, u);
	}
	divide();
	scanf("%d", &m);
	while (m --) {
		int u, v;
		scanf("%d%d", &u, &v);
		double l(1e-8), r(1e8);
		while (l + eps < r) {
			double mid((l + r + eps) / 2.0);
			if (check(u, v, mid))
				l = mid;
			else
				r = mid - eps;
		}
		printf("%.4lf\n", l);
	}
}

BZOJ1180 [CROATIAN2009]OTOCI & BZOJ2843 极地旅行社

难得的水水的双倍题。

 

看上去是想考lct然后忘强制在线了么?那就直接预处理出形态然后链剖呗。当然我还没有达到mhy这种认为lct比tcd好写的水平。

 

中间还把修改写挂了一次,然后1180的询问数是2843的3倍又re了一次。晕。

 

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct edge {
	int t;
	edge *next;
};
struct seg {
	int l, r, s[2];
	seg *ls, *rs;
};
struct query {
	char o;
	int a, b, s;
};

const int maxn = 30009;
const int maxm = 300009;

int n, m, r[maxn], d[maxn], v[maxn], u[maxn];
int fa[maxn], sz[maxn], tc, fc[maxn], ch[maxn], cl[maxn];
int qret[2];
seg slst[maxn << 2], *sp(slst), *rt[maxn];
edge elst[maxn << 1], *ep(elst), *head[maxn];
query q[maxm];

inline void addEdge(int u, int v) {
	ep-> t = v;
	ep-> next = head[u];
	head[u] = ep ++;
}

int getRoot(int x) {
	register int p, q;
	for (p = r[x]; r[p] ^ p; p = r[p]);
	for (; x ^ p; q = r[x], r[x] = p, x = q);
	return x;
}

void divide(int p0) {
	static int q[maxn];
	int hd(0), tl(1);
	q[0] = p0;
	d[p0] = 1;
	fa[p0] = 0;
	while (hd < tl) {
		int p(q[hd ++]);
		for (edge* e = head[p]; e; e = e-> next)
			if (e-> t != fa[p]) {
				d[e-> t] = d[p] + 1;
				fa[e-> t] = p;
				q[tl ++] = e-> t;
			}
	}
	for (int i = tl - 1; i >= 0; -- i) {
		int p(q[i]), z(-1);
		sz[p] = 1;
		for (edge* e = head[p]; e; e = e-> next)
			if (e-> t != fa[p]) {
				sz[p] += sz[e-> t];
				if (z == -1 || sz[e-> t] > sz[z])
					z = e-> t;
			}
		if (z == -1)
			cl[fc[p] = ++ tc] = 1;
		else
			++ cl[fc[p] = fc[z]];
		ch[fc[p]] = p;
	}
}

#define cpos(_p_) (d[_p_]-d[ch[fc[_p_]]])
#define midp(p) ((p->l+p->r)>>1)

inline seg* sgtBuild(int l, int r) {
	seg* p(sp ++);
	p-> l = l;
	p-> r = r;
	p-> s[0] = r - l;
	p-> s[1] = 0;
	if (l + 1 < r) {
		p-> ls = sgtBuild(l, midp(p));
		p-> rs = sgtBuild(midp(p), r);
	}
	return p;
}
inline void sgtChg(seg* p, int p0, int i, int v) {
	if (p-> l + 1 == p-> r)
		p-> s[i] = v;
	else {
		if (p0 < midp(p))
			sgtChg(p-> ls, p0, i, v);
		else
			sgtChg(p-> rs, p0, i, v);
		p-> s[i] = p-> ls-> s[i] + p-> rs-> s[i];
	}
}
inline void sgtQry(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r) {
		qret[0] += p-> s[0];
		qret[1] += p-> s[1];
	}
	else if (r <= midp(p))
		sgtQry(p-> ls, l, r);
	else if (l >= midp(p))
		sgtQry(p-> rs, l, r);
	else {
		sgtQry(p-> ls, l, midp(p));
		sgtQry(p-> rs, midp(p), r);
	}
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif

	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) {
		r[i] = i;
		scanf("%d", v + i);
		u[i] = 1;
	}
	scanf("%d", &m);
	for (int i = 0; i < m; ++ i) {
		char opt[11];
		scanf("%s%d%d", opt, &q[i]. a, &q[i]. b);
		q[i]. o = opt[0];
		if (q[i]. o == 'b') {
			if (getRoot(q[i]. a) ^ getRoot(q[i]. b)) {
				q[i]. s = 1;
				r[getRoot(q[i]. a)] = getRoot(q[i]. b);
				addEdge(q[i]. a, q[i]. b);
				addEdge(q[i]. b, q[i]. a);
			}
			else {
				q[i]. s = 0;
			}
		}
	}
	memset(d, 0, sizeof(d));
	tc = 0;
	for (int i = 1; i <= n; ++ i)
		if (!d[i])
			divide(i);
	for (int i = 1; i <= tc; ++ i)
		rt[i] = sgtBuild(0, cl[i]);
	for (int i = 1; i <= n; ++ i)
		sgtChg(rt[fc[i]], cpos(i), 1, v[i]);
	for (int i = 0; i < m; ++ i)
		if (q[i]. o == 'b') {
			if (q[i]. s) {
				if (d[q[i]. a] > d[q[i]. b])
					swap(q[i]. a, q[i]. b);
				u[q[i]. b] = 0;
				sgtChg(rt[fc[q[i]. b]], cpos(q[i]. b), 0, 0);
				puts("yes");
			}
			else
				puts("no");
		}
		else if (q[i]. o == 'p') {
			sgtChg(rt[fc[q[i]. a]], cpos(q[i]. a), 1, q[i]. b);
		}
		else if (q[i]. o == 'e') {
			int u(q[i]. a), v(q[i]. b);
			if (getRoot(u) != getRoot(v)) {
				puts("impossible");
			}
			else {
				qret[0] = qret[1] = 0;
				while (fc[u] ^ fc[v]) {
					if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
						sgtQry(rt[fc[u]], 0, cpos(u) + 1);
						u = fa[ch[fc[u]]];
					}
					else {
						sgtQry(rt[fc[v]], 0, cpos(v) + 1);
						v = fa[ch[fc[v]]];
					}
				}
				if (d[u] > d[v])
					swap(u, v);
				sgtQry(rt[fc[u]], cpos(u), cpos(v) + 1);
				qret[0] -= :: u[u];
				if (qret[0])
					puts("impossible");
				else
					printf("%d\n",  qret[1]);
			}
		}
}

BZOJ2157 旅游

去找水题于是找到这么一道恶心的代码题。其实应该可以用函数指针来优化一下代码量,不过懒得了。虽然复制粘贴导致调试了老半天。

 

水水的链剖+线段树。然后tag打一打就好了。

 

最近是装备了高超的开坑技巧啊。

 

#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

struct seg {
	int l, r, s, a, b, rv;
	seg *ls, *rs;
	inline void update() {
		if (l + 1 < r) {
			s = ls-> s + rs-> s;
			a = min(ls-> a, rs-> a);
			b = max(ls-> b, rs-> b);
			if (rv) {
				s = -s;
				swap(a, b);
				a = -a;
				b = -b;
			}
		}
		else
			a = b = s;
	}
	inline void chgTag() {
		s = -s;
		swap(a, b);
		a = -a;
		b = -b;
		rv ^= 1;
	}
	inline void downTag() {
		if (rv) {
			rv = 0;
			if (l + 1 < r) {
				ls-> chgTag();
				rs-> chgTag();
			}
		}
	}
};
struct edge {
	int t, v;
	edge *next;
};

const int maxn = 20009;

int n, m, fa[maxn], d[maxn], vl[maxn], ea[maxn], eb[maxn];
int sz[maxn], tc, fc[maxn], ch[maxn], cl[maxn];
edge elst[maxn << 1], *ep(elst), *head[maxn];
seg slst[maxn << 2], *sp(slst), *rt[maxn];

inline void addEdge(int u, int v, int w) {
	ep-> t = v;
	ep-> v = w;
	ep-> next = head[u];
	head[u] = ep ++;
}

#define midp(p) ((p->l+p->r)>>1)
inline seg* sgtBuild(int l, int r) {
	seg* p(sp ++);
	p-> l = l;
	p-> r = r;
	if (l + 1 < r) {
		p-> ls = sgtBuild(l, midp(p));
		p-> rs = sgtBuild(midp(p), r);
	}
	return p;
}
inline void sgtChg(seg* p, int p0, int v0) {
	if (p-> l + 1 == p-> r) {
		p-> rv = 0;
		p-> s = v0;
	}
	else {
		p-> downTag();
		if (p0 < midp(p))
			sgtChg(p-> ls, p0, v0);
		else
			sgtChg(p-> rs, p0, v0);
	}
	p-> update();
}
inline int sgtSum(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r)
		return p-> s;
	else {
	   p-> downTag();
	   if (r <= midp(p))
		   return sgtSum(p-> ls, l, r);
	   else if (l >= midp(p))
		   return sgtSum(p-> rs, l, r);
	   else
		   return sgtSum(p-> ls, l, midp(p)) + sgtSum(p-> rs, midp(p), r);
	}
}
inline int sgtMin(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r)
		return p-> a;
	else {
		p-> downTag();
		if (r <= midp(p))
			return sgtMin(p-> ls, l, r);
		else if (l >= midp(p))
			return sgtMin(p-> rs, l, r);
		else
			return min(sgtMin(p-> ls, l, midp(p)), sgtMin(p-> rs, midp(p), r));
	}
}
inline int sgtMax(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r)
		return p-> b;
	else {
		p-> downTag();
		if (r <= midp(p))
			return sgtMax(p-> ls, l, r);
		else if (l >= midp(p))
			return sgtMax(p-> rs, l, r);
		else
			return max(sgtMax(p-> ls, l, midp(p)), sgtMax(p-> rs, midp(p), r));
	}
}
inline void sgtRev(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r)
		p-> chgTag();
	else {
		p-> downTag();
		if (r <= midp(p))
			sgtRev(p-> ls, l, r);
		else if (l >= midp(p))
			sgtRev(p-> rs, l, r);
		else
			sgtRev(p-> ls, l, midp(p)), sgtRev(p-> rs, midp(p), r);
	}
	p-> update();
}

#define cpos(_p_) (d[_p_]-d[ch[fc[_p_]]])

void divide() {
	static int q[maxn];
	int hd(0), tl(1);
	q[0] = 0;
	memset(d, 0, sizeof(d));
	d[0] = 1;
	fa[0] = 0;
	vl[0] = 0;
	while (hd < tl) {
		int p(q[hd ++]);
		for (edge* e = head[p]; e; e = e-> next)
			if (!d[e-> t]) {
				fa[e-> t] = p;
				d[e-> t] = d[p] + 1;
				q[tl ++] = e-> t;
				vl[e-> t] = e-> v;
			}
	}
	tc = 0;
	for (int ti = tl - 1; ti >= 0; -- ti) {
		int p(q[ti]), z(-1);
		sz[p] = 1;
		for (edge* e = head[p]; e; e = e-> next)
			if (e-> t != fa[p]) {
				sz[p] += sz[e-> t];
				if (z == -1 || sz[e-> t] > sz[z])
					z = e-> t;
			}
		if (z == -1)
			cl[fc[p] = ++ tc] = 1;
		else
			++ cl[fc[p] = fc[z]];
		ch[fc[p]] = p;
	}
	for (int i = 1; i <= tc; ++ i)
		rt[i] = sgtBuild(0, cl[i]);
	for (int i = 0; i < n; ++ i)
		sgtChg(rt[fc[i]], cpos(i), vl[i]);
}

int main() {
#ifndef ONLINE_JUDGE
	freopen("in.txt", "r", stdin);
#endif

	scanf("%d", &n);
	memset(head, 0, sizeof(d));
	for (int i = 1; i < n; ++ i) {
		int w;
		scanf("%d%d%d", ea + i, eb + i, &w);
		addEdge(ea[i], eb[i], w);
		addEdge(eb[i], ea[i], w);
	}
	divide();
	scanf("%d", &m);
	while (m --) {
		char opt[7];
		int u, v, w;
		scanf("%s", opt);
		if (opt[0] == 'C') {
			scanf("%d%d", &u, &w);
			if (d[ea[u]] > d[eb[u]])
				swap(ea[u], eb[u]);
			v = eb[u];
			sgtChg(rt[fc[v]], cpos(v), w);
		}
		else if (opt[0] == 'N') {
			scanf("%d%d", &u, &v);
			while (fc[u] ^ fc[v])
				if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
					sgtRev(rt[fc[u]], 0, cpos(u) + 1);
					u = fa[ch[fc[u]]];
				}
				else {
					sgtRev(rt[fc[v]], 0, cpos(v) + 1);
					v = fa[ch[fc[v]]];
				}
			if (d[u] > d[v])
				swap(u, v);
			if (u ^ v)
				sgtRev(rt[fc[u]], cpos(u) + 1, cpos(v) + 1);
		}
		else if (opt[0] == 'S') {
			int s(0);
			scanf("%d%d", &u, &v);
			while (fc[u] ^ fc[v])
				if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
					s += sgtSum(rt[fc[u]], 0, cpos(u) + 1);
					u = fa[ch[fc[u]]];
				}
				else {
					s += sgtSum(rt[fc[v]], 0, cpos(v) + 1);
					v = fa[ch[fc[v]]];
				}
			if (d[u] > d[v])
				swap(u, v);
			if (u ^ v)
				s += sgtSum(rt[fc[u]], cpos(u) + 1, cpos(v) + 1);
			printf("%d\n", s);
		}
		else if (opt[1] == 'I') {
			int s(0x3f3f3f3f);
			scanf("%d%d", &u, &v);
			while (fc[u] ^ fc[v])
				if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
					s = min(s, sgtMin(rt[fc[u]], 0, cpos(u) + 1));
					u = fa[ch[fc[u]]];
				}
				else {
					s = min(s, sgtMin(rt[fc[v]], 0, cpos(v) + 1));
					v = fa[ch[fc[v]]];
				}
			if (d[u] > d[v])
				swap(u, v);
			if (u ^ v)
				s = min(s, sgtMin(rt[fc[u]], cpos(u) + 1, cpos(v) + 1));
			printf("%d\n", s);
		}
		else if (opt[1] == 'A') {
			int s(-0x3f3f3f3f);
			scanf("%d%d", &u, &v);
			while (fc[u] ^ fc[v])
				if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
					s = max(s, sgtMax(rt[fc[u]], 0, cpos(u) + 1));
					u = fa[ch[fc[u]]];
				}
				else {
					s = max(s, sgtMax(rt[fc[v]], 0, cpos(v) + 1));
					v = fa[ch[fc[v]]];
				}
			if (d[u] > d[v])
				swap(u, v);
			if (u ^ v)
				s = max(s, sgtMax(rt[fc[u]], cpos(u) + 1, cpos(v) + 1));
			printf("%d\n", s);
		}
	}
}