BZOJ1604 [Usaco2008 Open]Cow Neighborhoods 奶牛的邻居

在一道usaco的题上wa了三次。我也是厉害。

 

其实好像有简单做法的。不过我是要脑补一下曼哈顿最小生成树。

 

对于一个平面图上的点的曼哈顿最小生成树,一定存在一种方案,使得每个点的度数至多为8。也就是说以斜率为0,inf,1,-1的四条直线分出来的八个区域里各有一个点就行了。然后是可以保证的。

 

于是就是拿俩树状数组扫四遍就行了。

 

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

using namespace std;

const int inf = 0x3f3f3f3f;

struct point {
	int x, y, i;
	point() {
		x = -inf, y = -1;
	}
	point(int xo, int yo) {
		x = xo, y = yo;
	}
	inline void init(int ix) {
		scanf("%d%d", &x, &y);
		i = ix;
	}
};

inline bool operator <(const point& a, const point& b) {
	return (a. x < b. x) || (a. x == b. x && a. y < b. y);
}

const int maxn = 100009;
const int maxx = 1e9;

int n, c, r[maxn], sz[maxn], cnt, msz;
int v[maxn], tv, w[maxn], tw;
point a[maxn], ta[maxn], tb[maxn];

int getRoot(int x) {
	register int p, q;
	for (p = r[x]; p ^ r[p]; p = r[p]);
	for (; x ^ p; q = r[x], r[x] = p, x = q);
	return x;
}
inline void join(int u, int v) {
	r[getRoot(u)] = getRoot(v);
}

point btQry(point* t, int p) {
	point s(-inf, -1);
	for (++ p; p; p -= (p & -p))
		if (s < t[p])
			s = t[p];
	return s;
}
void btChg(point* t, int p, point v) {
	for (++ p; p < maxn; p += (p & -p))
		if (t[p] < v)
			t[p] = v;
}

inline bool isNeighbour(const point& a, const point& b) {
	return abs(a. x - b. x) + abs(a. y - b. y) <= c;
}

void span() {
	sort(a, a + n);
	tv = tw;
	for (int i = 0; i < n; ++ i) {
		v[i] = a[i]. y - a[i]. x;
		w[i] = - a[i]. x - a[i]. y;
	}
	sort(v, v + n);
	tv = unique(v, v + n) - v;
	sort(w, w + n);
	tw = unique(w, w + n) - w;
	for (int i = 1; i <= tv || i <= tw; ++ i)
		ta[i] = tb[i] = point();
	for (int i = 0; i < n; ++ i) {
		int p(lower_bound(v, v + tv, a[i]. y - a[i]. x) - v);
		point g(btQry(ta, p));
		if (g. y > -1 && isNeighbour(a[i], a[g. y]))
		   join(a[i]. i, a[g. y]. i);	
		btChg(ta, p, point(a[i]. x + a[i]. y, i));
		p = lower_bound(w, w + tw, - a[i]. x - a[i]. y) - w;
		g = btQry(tb, p);
		if (g. y > -1 && isNeighbour(a[i], a[g. y]))
		   join(a[i]. i, a[g. y]. i);	
		btChg(tb, p, point(a[i]. x - a[i]. y, i));
	}
}

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

	scanf("%d%d", &n, &c);
	for (int i = 0; i < n; ++ i) {
		a[i]. init(i);
		r[i] = i;
	}
	span();
	for (int i = 0; i < n; ++ i)
		a[i]. x = maxx - a[i]. x;
	span();
	for (int i = 0; i < n; ++ i)
		swap(a[i]. x, a[i]. y);
	span();
	for (int i = 0; i < n; ++ i)
		a[i]. x = maxx - a[i]. x;
	span();
	memset(sz, 0, sizeof(sz));
	for (int i = 0; i < n; ++ i) {
		if (r[i] == i)
			++ cnt;
		++ sz[getRoot(i)];
	}
	for (int i = 0; i < n; ++ i)
		if (r[i] == i && sz[i] > msz)
			msz = sz[i];
	printf("%d %d\n", cnt, msz);
}

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);
	}
}

BZOJ1513 [POI2006]Tet-Tetris 3D

这么水的题居然还要写题解。要不要说我写了半个下午+半个晚上。

 

丧心病狂想写一发zkw去抢速度rank。然后发现zkw怎么支持区间修改查询TT。课件根本没讲懂。而且max怎么区间加。

 

想了很久终于想出了来了。然后交上去发现常数巨大比普通线段树还要慢TT。到头来想想如果我直接写普通线段树说不定十多分钟就能过,而且代码量还会小一些。因为那个是可以直接通用的,但是这个比较麻烦。

 

其实写这个就题解就是想记录一下我yy出来的zkw区间修改区间查询的方法。

 

这道题是区间查询最大值+区间修改。如果是写一般的线段树,需要记录两个值a和v(至于为啥我用了这俩神奇的字母我也不知道),分别表示当前区间被完整覆盖的修改的最大值(又称lazy标记)和当前区间的最大值。然后所以zkw也要记这两个东西。

 

如果我们把zkw看作一棵树,那么每次修改和询问操作的时候都是对一些线段的a和v进行操作。(废话)

 

首先考虑修改。zkw经典的变为开区间取中间能处理a值的改变,但是不能处理v值的改变。因为v值改变的线段不一定会被当前区间包含。然后仔细考虑发现a值没有变但是v值变了的点只可能存在于两个端点到根的路径上。那就直接强行更新一发就好了啊。然后更新的区域就变成了一个有点像倒置漏斗的形状。

 

再考虑询问。a要覆盖当前区间,v要被当前区间覆盖。那不就是修改把a和v的做法反一下么。

 

然后好像也不是很麻烦的样子哈。

 

然后常数很大哈。

 

那还拿zkw做何用。

 

晕。

 

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

using namespace std;

const int buf_len = 4567;
char buf[buf_len], *bufb(buf), *bufe(buf + 1);
#define readBuf() { \
	if (++ bufb == bufe) \
		bufe = (bufb = buf) + fread(buf, 1, sizeof(buf), stdin); \
}
#define readInt(_x_) { \
	register int _s_(0); \
	do { \
		readBuf(); \
	} while (!isdigit(*bufb)); \
	do { \
		_s_ = _s_ * 10 + *bufb - 48; \
		readBuf(); \
	} while (isdigit(*bufb)); \
	_x_ = _s_; \
}

const int maxn = 2049;

int q, n, m, bn, bm;

inline void upMax(int& a, int b) {
	if (a < b)
		a = b;
}
#define upMax_d(_a_,_b_) { \
	if (_a_ < _b_) \
		_a_ = _b_; \
}

struct zkw_tree_y {
	int v[maxn], a[maxn];
	zkw_tree_y() {
		memset(v, 0, sizeof(v));
		memset(a, 0, sizeof(a));
	}
	int qry(int lo, int ro) {
		int s(0), l, r;
		for (l = lo + bm; l; l >>= 1)
			upMax_d(s, a[l]);
		for (r = ro + bm; r; r >>= 1)
			upMax_d(s, a[r]);
		for (l = lo + bm - 1, r = ro + bm + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
			if (!(l & 1))
				upMax_d(s, v[l ^ 1]);
			if (r & 1)
				upMax_d(s, v[r ^ 1]);
		}
		return s;
	}
	void chg(int lo, int ro, int h) {
		int l, r;
		for (l = lo + bm; l; l >>= 1)
			upMax_d(v[l], h);
		for (r = ro + bm; r; r >>= 1)
			upMax_d(v[r], h);
		for (l = lo + bm - 1, r += ro + bm + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
			if (!(l & 1)) {
				upMax_d(a[l ^ 1], h);
				upMax_d(v[l ^ 1], h);
			}
			if (r & 1) {
				upMax_d(a[r ^ 1], h);
				upMax_d(v[r ^ 1], h);
			}
		}
	}
};

zkw_tree_y v[maxn], a[maxn];

int zkwQryX(int lo, int ro, int yl, int yr) {
	int s(0), l, r;
	for (l = lo + bn; l; l >>= 1)
		upMax(s, a[l]. qry(yl, yr));
	for (r = ro + bn; r; r >>= 1)
		upMax(s, a[r]. qry(yl, yr));
	for (l = lo + bn - 1, r = ro + bn + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (!(l & 1))
			upMax(s, v[l ^ 1]. qry(yl, yr));
		if (r & 1)
			upMax(s, v[r ^ 1]. qry(yl, yr));
	}
	return s;
}
void zkwChgX(int lo, int ro, int yl, int yr, int h) {
	int l, r;
	for (l = lo + bn; l; l >>= 1)
		v[l]. chg(yl, yr, h);
	for (r = ro + bn; r; r >>= 1)
		v[r]. chg(yl, yr, h);
	for (l = lo + bn - 1, r = ro + bn + 1; l ^ r ^ 1; l >>= 1, r >>= 1) {
		if (!(l & 1)) {
			a[l ^ 1]. chg(yl, yr, h);
			v[l ^ 1]. chg(yl, yr, h);
		}
		if (r & 1) {
			a[r ^ 1]. chg(yl, yr, h);
			v[r ^ 1]. chg(yl, yr, h);
		}
	}
}

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

	readInt(n);
	readInt(m);
	readInt(q);
	memset(a, 0, sizeof(a));
	memset(v, 0, sizeof(v));
	for (bn = 1; bn < n + 2; bn <<= 1);
	for (bm = 1; bm < m + 2; bm <<= 1);
	while (q --) {
		int x, y, p, q, h;
		readInt(p);
		readInt(q);
		readInt(h);
		readInt(x);
		readInt(y);
		p += x ++, q += y ++;
		h += zkwQryX(x, p, y, q);
		zkwChgX(x, p, y, q, h);
	}
	printf("%d\n", zkwQryX(1, n, 1, m));
}

BZOJ1023 [SHOI2008]cactus仙人掌图

第六百道题一定要不水!虽然离第一页还有几十道题的距离。

 

很早之前见过的题吧。然后一直觉得特别难写所以都没写。以前写点不重复的仙人掌都觉得挺痛苦,更不要说这个了。

 

现在想想还行,因为我yy出了化简的方法。先搞出dfs树。然后一个顶点如果是一个环里深度最浅的,那么称它为这个环的头。可以证明一个顶点最多在一个不以它为头的环上。把这个环记下来,其它的环都从这个顶点去找边来找就行了。这样的话可以比较节省代码量,写起来也比较明了。虽然还是比mhy长。

 

然后因为我在最后一步dp的时候写了一个static的f数组,所以光荣了。debug了好久。晕。

 

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

using namespace std;

struct edge {
	int t, av;
	edge *next, *rv;
};
struct ball {
	int l, *a, h;
};

const int maxn = 50009;
const int maxm = 200009;
const int maxarr = 400009;

int n, m, cb, fb[maxn], d[maxn];
int f[maxn], ans, fd[maxn], fe[maxn];
int stc[maxn], tst;
int ibuf_arr[maxarr], *ibuf(ibuf_arr);
bool vis[maxn];
edge elst[maxm], *ep(elst), *head[maxn];
ball b[maxm];

inline edge* addEdge(int u, int v) {
	ep-> t = v;
	ep-> av = 1;
	ep-> next = head[u];
	return head[u] = ep ++;
}

inline void upMax(int& a, int b) {
	if (a < b)
		a = b;
}

void dfsBall(int p) {
	vis[p] = 1;
	stc[++ tst] = p;
	for (edge *e = head[p]; e; e = e-> next)
		if (e-> av) {
			e-> rv-> av = 0;
			if (vis[e-> t] && (!fb[p])) {
				e-> av = 0;
				b[++ cb]. l = 0;
				b[cb]. a = ibuf;
				for (int i = tst; 1; -- i) {
					b[cb]. a[b[cb]. l ++] = stc[i];
					if (stc[i] != e-> t)
						fb[stc[i]] = cb;
					else
						break;
				}
				b[cb]. h = e-> t;
				ibuf += b[cb]. l;
			}
			else {
				d[e-> t] = d[p] + 1;
				dfsBall(e-> t);
			}
		}
	-- tst;
}

void downDP(int p) {
	fd[p] = fe[p] = 0;
	for (edge* e = head[p]; e; e = e-> next)
		if (e-> av) {
			if (fb[e-> t] && p == b[fb[e-> t]]. h) {
				int bi(fb[e-> t]), fl(0);
				for (int i = 0; i < b[bi]. l; ++ i)
					if (b[bi]. a[i] != b[bi]. h) {
						int q(b[bi]. a[i]);
						downDP(q);
						upMax(fl, fd[q] + min(d[q] - d[p], b[bi]. l - d[q] + d[p]));
					}
				if (fl > fd[p]) {
					fe[p] = fd[p];
					fd[p] = fl;
				}
				else if (fl > fe[p])
					fe[p] = fl;
			}
			else if (!fb[p] || fb[p] != fb[e-> t]) {
				downDP(e-> t);
				int v(fd[e-> t] + 1);
				if (v > fd[p]) {
					fe[p] = fd[p];
					fd[p] = v;
				}
				else if (v > fe[p])
					fe[p] = v;
			}
		}
	upMax(ans, fd[p] + fe[p]);
}

#define modi(_i_) (((_i_)>=b[bi].l)?((_i_)-b[bi].l):(_i_))
void upDP(int p, int u) {
	static int q[maxn << 1], fu[maxn << 1];
	for (edge* e = head[p]; e; e = e-> next)
		if (e-> av) {
			if (fb[e-> t] && p == b[fb[e-> t]]. h) {
				int bi(fb[e-> t]), fl(0);
				int *f(ibuf);
				ibuf += b[bi]. l;
				for (int i = 0; i < b[bi]. l; ++ i) {
					int q(b[bi]. a[i]);
					f[i] = 0;
					if (q == p)
						break;
					fu[i] = fd[q];
					upMax(fl, fd[q] + min(d[q] - d[p], b[bi]. l - d[q] + d[p]));
				}
				if (fl == fd[p])
					fu[b[bi]. l - 1] = max(u, fe[p]);
				else
					fu[b[bi]. l - 1] = max(u, fd[p]);
				int hd(0), tl(1), hl(b[bi]. l >> 1);
				q[0] = 0;
				for (int i = 1; i < (b[bi]. l << 1); ++ i) {
					int fi(modi(i));
					while (hd < tl && i - q[hd] > hl)
						++ hd;
					if (hd < tl)
						upMax(f[fi], fu[modi(q[hd])] + i - q[hd]);
					while (hd < tl && fu[modi(q[tl - 1])] - q[tl - 1] <= fu[fi] - i)
						-- tl;
					q[tl ++] = i;
				}
				hd = 0;
				tl = 1;
				q[0] = (b[bi]. l << 1) - 1;
				for (int i = (b[bi]. l << 1) - 2; i >= 0; -- i) {
					int fi(modi(i));
					while (hd < tl && q[hd] - i > hl)
						++ hd;
					if (hd < tl)
						upMax(f[fi], fu[modi(q[hd])] + q[hd] - i);
					while (hd < tl && fu[modi(q[tl - 1])] + q[tl - 1] <= fu[fi] + i)
						-- tl;
					q[tl ++] = i;
				}
				for (int i = 0; i < b[bi]. l - 1; ++ i) {
					upMax(ans, f[i] + fd[b[bi]. a[i]]);
					upDP(b[bi]. a[i], f[i]);
				}
				ibuf -= b[bi]. l;
			}
			else if (!fb[p] || fb[e-> t] != fb[p]) {
				int v((fd[e-> t] + 1 == fd[p]) ? fe[p] : fd[p]);
				upDP(e-> t, max(u, v) + 1);
			}
		}
}

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

	scanf("%d%d", &n, &m);
	memset(head, 0, sizeof(head));
	for (int i = 0; i < m; ++ i) {
		int c, u, v;
		scanf("%d%d", &c, &u);
		while (-- c) {
			scanf("%d", &v);
			edge *a(addEdge(u, v)), *b(addEdge(v, u));
			a-> rv = b;
			b-> rv = a;
			u = v;
		}
	}
	memset(vis, 0, sizeof(vis));
	memset(fb, 0, sizeof(fb));
	cb = 0;
	tst = 0;
	d[1] = 1;
	dfsBall(1);
	ans = 0;
	downDP(1);
	upDP(1, 0);
	printf("%d\n", ans);
}

BZOJ3242 [Noi2013]快餐店

好吧我的本意是想学习一下dp的。然后发现了这道纠结了一年半还多的题。

 

首先把环找出来。然后环上会长一些树。先把树的答案求了,因为它很好求。

 

然后考虑环,那么答案应该是随便断一条边之后答案的最小值(而不是最大值)。于是乎记录一下每个点按某个方向到起点的距离,记为d[i]。算一下每个点的树的深度,记为l[i]。于是每次要最大化l[i]+l[j]+|d[i]-d[j]|。反正是最大化所以顺序是没有关系的,但是不能自交。这是个比较容易错的地方。于是就去写个线段树来维护吧。只查询不修改让我总有能线性搞的想法,虽然没想清楚具体怎么实现。

 

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

using namespace std;

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

typedef long long dint;
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define _l (long long int)

const int maxn = 100009;

edge elst[maxn << 1], *ep(elst), *head[maxn];
int n, fa[maxn], df[maxn], ol[maxn], d[maxn];
int tlp, lp[maxn << 1];
dint lv[maxn << 1], le[maxn << 1], md[maxn], ans;

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

void findLoop() {
	static int q[maxn];
	int hd(0), tl(1);
	int uo(0), vo(0), dx, a;
	q[0] = 1;
	fa[1] = -1;
	d[1] = 1;
	memset(ol, 0, sizeof(ol));
	memset(fa, 0, sizeof(fa));
	while (hd < tl && !uo) {
		int p(q[hd ++]);
		for (edge* e = head[p]; e; e = e-> next)
			if (e-> t ^ fa[p]) {
				if (fa[e-> t]) {
					uo = p;
					vo = e-> t;
					dx = e-> v;
					break;
				}
				else {
					d[e-> t] = d[p] + 1;
					fa[e-> t] = p;
					df[e-> t] = e-> v;
					q[tl ++] = e-> t;
				}
			}
	}
	tlp = 0;
	for (int u = uo, v = vo; u ^ v; ++ tlp)
		if (d[u] > d[v])
			a = u = fa[u];
		else
			a = v = fa[v];
	++ tlp;
	for (int u = uo, v = vo; u ^ v; )
		if (d[u] > d[v]) {
			int i(d[uo] - d[u]);
			lp[i] = u;
			le[i] = df[u];
			u = fa[u];
		}
		else {
			int i(tlp - d[vo] + d[v] - 1);
			lp[i] = v;
			le[i - 1] = df[v];
			v = fa[v];
		}
	lp[d[uo] - d[a]] = a;
	le[tlp - 1] = dx;
	for (int i = 0; i < tlp; ++ i)
		ol[lp[i]] = 1;
}

void dpTree(int p0) {
	static int q[maxn];
	int hd(0), tl(1);
	q[0] = p0;
	while (hd < tl) {
		int p(q[hd ++]);
		for (edge* e = head[p]; e; e = e-> next)
			if (!ol[e-> t]) {
				ol[e-> t] = ol[p] + 1;
				q[tl ++] = e-> t;
			}
	}
	for (int i = tl - 1; i >= 0; -- i) {
		int p(q[i]);
		dint s2(0);
		md[p] = 0;
		for (edge* e = head[p]; e; e = e-> next)
			if (ol[e-> t] == ol[p] + 1) {
				dint v(md[e-> t] + e-> v);
				if (v > md[p]) {
					s2 = md[p];
					md[p] = v;
				}
				else if (v > s2)
					s2 = v;
			}
		if (md[p] + s2 > ans)
			ans = md[p] + s2;
	}
}

struct dat {
	dint x, y, s;
	dat() {}
	dat(dint x0, dint y0) {
		x = x0, y = y0, s = 0;
	}
	dat(dat a, dat b) {
		s = max(max(a. s, b. s), a. x + b. y);
		x = max(a. x, b. x);
		y = max(a. y, b. y);
	}
};
struct seg {
	int l, r;
	dat d;
	seg *ls, *rs;
};
seg slst[maxn * 5], *sp(slst), *rt;

#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-> d = dat(lv[l] + le[l], lv[l] - le[l]);
	}
	else {
		p-> ls = sgtBuild(l, midp(p));
		p-> rs = sgtBuild(midp(p), r);
		p-> d = dat(p-> ls-> d, p-> rs-> d);
	}
	return p;
}
inline dat sgtQry(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r)
		return p-> d;
	else if (r <= midp(p))
		return sgtQry(p-> ls, l, r);
	else if (l >= midp(p))
		return sgtQry(p-> rs, l, r);
	else
		return dat(sgtQry(p-> ls, l, midp(p)), sgtQry(p-> rs, midp(p), r));
}

void dpLoop() {
	dint totl(0);
	for (int i = 0; i < tlp; ++ i) {
		lv[i + tlp] = lv[i];
		le[i + tlp] = le[i];
		lp[i + tlp] = lp[i];
		totl += le[i];
	}
	le[tlp * 2] = 0;
	for (int i = tlp * 2 - 1; i >= 0; -- i)
		le[i] += le[i + 1];
	rt = sgtBuild(0, tlp * 2);
	dint cans(0x7fffffffffffffffll);
	for (int i = 0; i < tlp; ++ i) {
		cans = min(cans, sgtQry(rt, i, i + tlp). s);
	}
	ans = max(ans, cans);
}

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

	scanf("%d", &n);
	memset(head, 0, sizeof(head));
	for (int i = 0; i < n; ++ i) {
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		addEdge(u, v, w);
		addEdge(v, u, w);
	}
	findLoop();
	ans = 0;
	for (int i = 0; i < tlp; ++ i) {
		dpTree(lp[i]);
		lv[i] = md[lp[i]];
	}
	dpLoop();
	printf("%.1lf\n", (double)ans / 2.0);
}

BZOJ2770 YY的Treap

今天考试题的弱化版。只用求LCA是谁,不用求它的深度。所以直接用线段树找下区间最值就搞定了。然后long的范围有负数坑了一发。

 

好像在不平衡的平衡树上的题也比较热啊。而且我还做得比较少。是要补一补。

 

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

using namespace std;

typedef pair <int, int> vpr;
typedef pair <bool, vpr> dpr;
struct seg {
	int l, r;
	dpr d;
	seg *ls, *rs;
};
struct query {
	int t, a, b;
};

const int maxn = 400009;

int n, m, vl[maxn], tv;
vpr a[maxn];
query q[maxn];
seg slst[maxn * 3], *sp(slst), *rt;

inline int gpos(int x) {
	return lower_bound(vl, vl + tv, x) - vl;
}

#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-> d = dpr(1, vpr(0, 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, dpr v0) {
	if (p-> l + 1 == p-> r)
		p-> d = v0;
	else {
		if (p0 < midp(p))
			sgtChg(p-> ls, p0, v0);
		else 
			sgtChg(p-> rs, p0, v0);
		p-> d = min(p-> ls-> d, p-> rs-> d);
	}
}
inline dpr sgtQry(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r)
		return p-> d;
	else if (r <= midp(p))
		return sgtQry(p-> ls, l, r);
	else if (l >= midp(p))
		return sgtQry(p-> rs, l, r);
	else
		return min(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%d", &n, &m);
	tv = 0;
	for (int i = 0; i < n; ++ i) {
		scanf("%d", &a[i]. second);
		vl[tv ++] = a[i]. second;
	}
	for (int i = 0; i < n; ++ i)
		scanf("%d", &a[i]. first);
	for (int i = 0; i < m; ++ i) {
		char opt[3];
		scanf("%s", opt);
		if (opt[0] == 'I') {
			q[i]. t = 1;
			scanf("%d%d", &q[i]. a, &q[i]. b);
			vl[tv ++] = q[i]. a;
		}
		else if (opt[0] == 'D') {
			q[i]. t = 2;
			scanf("%d", &q[i]. a);
		}
		else {
			q[i]. t = 3;
			scanf("%d%d", &q[i]. a, &q[i]. b);
		}
	}
	sort(vl, vl + tv);
	tv = unique(vl, vl + tv) - vl;
	rt = sgtBuild(0, tv);
	for (int i = 0; i < n; ++ i)
		sgtChg(rt, gpos(a[i]. second), dpr(0, a[i]));
	for (int i = 0; i < m; ++ i)
		if (q[i]. t == 1)
			sgtChg(rt, gpos(q[i]. a), dpr(0, vpr(q[i]. b, q[i]. a)));
		else if (q[i]. t == 2)
			sgtChg(rt, gpos(q[i]. a), dpr(1, vpr(0, 0)));
		else {
			int u(gpos(q[i]. a)), v(gpos(q[i]. b));
			if (u > v)
				swap(u, v);
			printf("%d\n", sgtQry(rt, u, v + 1). second. second);
		}
}

BZOJ3888 [Usaco2015 Jan]Stampede

usaco的银组都开始考这种题了么。其实还是挺水的,不过题号比较好。

 

就按y排序,挨个把时间轴上的东西扔掉就完了。写离散可能还没有直接写smt快呢。

 

然后线段有一边要减1有点坑。

 

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

using namespace std;

typedef long long dint;
#define _l (long long int)

struct cow {
	int y;
	int ta, tb;
};

struct node {
	int l, r, w;
	node *ls, *rs;
};
typedef pair <node*, node* > npr;

const int maxn = 50009;

inline bool operator <(const cow& a, const cow& b) {
	return a. y < b. y;
}

int n, ans;
cow a[maxn];
node nlst[maxn << 1], *np(nlst), *rt;

node* newNode(int l, int r) {
	np-> l = l;
	np-> r = r;
#ifdef WIN32
	np-> w = (rand() << 16) | rand();
#else
	np-> w = rand();
#endif
	np-> ls = np-> rs = 0;
	return np ++;
}

npr split(node* p, int x) {
	if (!p)
		return npr(0, 0);
	else if (x < p-> l) {
		npr g(split(p-> ls, x));
		p-> ls = g. second;
		return npr(g. first, p);
	}
	else if (x >= p-> r) {
		npr g(split(p-> rs, x));
		p-> rs = g. first;
		return npr(p, g. second);
	}
	else {
		node *q(newNode(p-> l, x));
		q-> ls = p-> ls;
		p-> ls = 0;
		p-> l = x + 1;
		return npr(q, p);
	}
}
node *merge(node* p, node* q) {
	if (!p)
		return q;
	else if (!q)
		return p;
	else if (p-> w > q-> w) {
		p-> rs = merge(p-> rs, q);
		return p;
	}
	else {
		q-> ls = merge(p, q-> ls);
		return q;
	}
}

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

	srand(239473);
	scanf("%d", &n);
	for (int i = 0; i < n; ++ i) {
		int x, r;
		scanf("%d%d%d", &x, &a[i]. y, &r);
		a[i]. ta = - x * r - r + 1;
		a[i]. tb = - x * r;
	}
	rt = newNode(-1, 1000000009);
	ans = 0;
	sort(a, a + n);
	for (int i = 0; i < n; ++ i) {
		npr x(split(rt, a[i]. ta - 1));
		npr y(split(x. second, a[i]. tb));
		if (y. first)
			++ ans;
		rt = merge(x. first, y. second);
	}
	printf("%d\n", ans);
}

BZOJ1455 罗马游戏

左偏树+并查集的一眼题嘛。然后合并的时候搞忘了如果两个人已经在同一个团里要跳过,于是左偏树自交去了。

 

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

using namespace std;

#define szof(p) ((p)?(p->sz):0)
struct node {
	int sz, vl, id;
	node *ls, *rs;
	node() {}
	node(int v, int i) {
		vl = v;
		id = i;
		sz = 1;
		ls = rs = 0;
	}
	inline void update() {
		if (szof(ls) < szof(rs))
			swap(ls, rs);
	}
};
node *merge(node* p, node* q) {
	if (!p)
		return q;
	else if (!q)
		return p;
	else if (p-> vl < q-> vl) {
		p-> rs = merge(p-> rs, q);
		p-> update();
		return p;
	}
	else {
		q-> rs = merge(q-> rs, p);
		q-> update();
		return q;
	}
}
node *pop(node* p) {
	if (p)
		return merge(p-> ls, p-> rs);
	else
		return 0;
}

const int maxn = 1000009;

int n, m, r[maxn];
bool al[maxn];
node nlst[maxn], *rt[maxn];

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

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

	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) {
		int w;
		scanf("%d", &w);
		nlst[i] = node(w, i);
		rt[i] = &nlst[i];
		al[i] = 1;
		r[i] = i;
	}
	scanf("%d", &m);
	while (m --) {
		char opt[3];
		int a, b;
		scanf("%s", opt);
		if (opt[0] == 'M') {
			scanf("%d%d", &a, &b);
			if (al[a] && al[b]) {
				a = getRoot(a);
				b = getRoot(b);
				if (a == b)
					continue;
				r[a] = b;
				rt[b] = merge(rt[b], rt[a]);
			}
		}
		else if (opt[0] == 'K') {
			scanf("%d", &a);
			if (!al[a])
				puts("0");
			else {
				a = getRoot(a);
				printf("%d\n", rt[a]-> vl);
				al[rt[a]-> id] = 0;
				rt[a] = pop(rt[a]);
			}
		}
	}
}

BZOJ3757 苹果树

今天晚上的效率比白天高啊。

 

树上莫队的另一道题。比糖果公园好写到哪里去了。

 

然后手写链表丑掉了导致调试半天+RE了一发。我还是太年轻了。

 

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

using namespace std;

typedef struct node {
	int t;
	node *next;
} edge;
const int maxn = 50009;
const int maxm = 100009;
const int maxl = 17;
node nlst[maxn], *np(nlst);
struct chain {
	int sz;
	node *hd, *tl;
	chain() {
		hd = tl = 0;
		sz = 0;
	}
	inline void clear() {
		hd = tl = 0;
		sz = 0;
	}
	inline void push(int x) {
		np-> t = x;
		np-> next = 0;
		if (sz) {
			tl-> next = np;
			tl = np;
		}
		else {
			hd = np;
			tl = np;
		}
		++ np;
		++ sz;
	}
	inline void merge(chain a) {
		if (a. sz) {
			if (sz) {
				tl-> next = a. hd;
				tl = a. tl;
			}
			else {
				hd = a. hd;
				tl = a. tl;
			}
			sz += a. sz;
		}
	}
};
struct query {
	int a, b, x, y, i;
};

int n, m, bsz, ans[maxm], cnt[maxn], fb[maxn], col[maxn], tb;
int d[maxn], ath[maxn][maxl];
edge elst[maxn << 1], *ep(elst), *head[maxn];
query q[maxm];

inline bool operator <(const query& a, const query& b) {
	return (fb[a. a] < fb[b. a]) || (fb[a. a] == fb[b. a] && fb[a. b] < fb[b. b]);
}

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

chain dfs(int p) {
	for (int i = 1; i < maxl; ++ i)
		ath[p][i] = ath[ath[p][i - 1]][i - 1];
	chain w;
	for (edge* e = head[p]; e; e = e-> next)
		if (e-> t != ath[p][0]) {
			ath[e-> t][0] = p;
			d[e-> t] = d[p] + 1;
			chain g(dfs(e-> t));
			w. merge(g);
			if (w. sz >= bsz) {
				++ tb;
				for (node* it = w. hd; it; it = it-> next)
					fb[it-> t] = tb;
				w. clear();
			}
		}
	w. push(p);
	return w;
}
void divide() {
	d[0] = 1;
	tb = 0;
	chain g(dfs(0));
	for (node* it = g. hd; it; it = it-> next)
		fb[it-> t] = tb;
}

int LCA(int u, int v) {
	if (d[u] < d[v])
		swap(u, v);
	for (int i = maxl - 1; i >= 0; -- i)
		if (d[ath[u][i]] >= d[v])
			u = ath[u][i];
	if (u == v)
		return u;
	for (int i = maxl - 1; i >= 0; -- i)
		if (ath[u][i] ^ ath[v][i]) {
			u = ath[u][i];
			v = ath[v][i];
		}
	return ath[u][0];
}
inline void rmVertex(int p, int& ans) {
	if (p && ! -- cnt[col[p]])
		-- ans;
}
inline void insVertex(int p, int& ans) {
	if (p && !(cnt[col[p]] ++))
		++ ans;
}
void moveVertex(int& u, int v, int g, int& ans) {
	int a(LCA(u, v)), t(LCA(a, g));
	if (a == t) {
		int x(LCA(u, g)), y(LCA(v, g));
		if (d[x] > d[y])
			t = x;
		else
			t = y;
		if (LCA(t, u) == t) {
			for (int p = g; p ^ t; p = ath[p][0])
				insVertex(p, ans);
			for (int p = u; p ^ t; p = ath[p][0])
				rmVertex(p, ans);
		}
		else {
			for (int p = g; p ^ t; p = ath[p][0])
				insVertex(p, ans);
			for (int p = u; p ^ a; p = ath[p][0])
				rmVertex(p, ans);
			for (int p = ath[t][0]; p ^ a; p = ath[p][0])
				rmVertex(p, ans);
			rmVertex(a, ans);
		}
	}
	else {
		for (int p = u; p ^ a; p = ath[p][0])
			rmVertex(p, ans);
		for (int p = g; p ^ t; p = ath[p][0])
			insVertex(p, ans);
		insVertex(t, ans);
		for (int p = ath[a][0]; p ^ t; p = ath[p][0])
			insVertex(p, ans);
	}
	u = g;
}
void cptMo() {
	int u(1), v(1), cans(1);
	memset(cnt, 0, sizeof(cnt));
	cnt[col[1]] = 1;
	sort(q, q + m);
	for (int i = 0; i < m; ++ i) {
		moveVertex(u, v, q[i]. a, cans);
		moveVertex(v, u, q[i]. b, cans);
		ans[q[i]. i] = cans;
		if ((q[i]. x || q[i]. y) && q[i]. x != q[i]. y)
			ans[q[i]. i] -= (cnt[q[i]. x] && cnt[q[i]. y]);
	}
}

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

	scanf("%d%d", &n, &m);
	bsz = (int)pow(n, 0.5) + 1;
	for (int i = 1; i <= n; ++ i)
		scanf("%d", col + i);
	memset(head, 0, sizeof(head));
	for (int i = 0; i < n; ++ i) {
		int u, v;
		scanf("%d%d", &u, &v);
		addEdge(u, v);
		addEdge(v, u);
	}
	for (int i = 0; i < m; ++ i) {
		scanf("%d%d%d%d", &q[i]. a, &q[i]. b, &q[i]. x, &q[i]. y);
		q[i]. i = i;
	}
	divide();
	for (int i = 0; i < m; ++ i)
		if (fb[q[i]. a] > fb[q[i]. b])
			swap(q[i]. a, q[i]. b);
	cptMo();
	for (int i = 0; i < m; ++ i)
		printf("%d\n", ans[i]);
}

BZOJ3052 [wc2013]糖果公园

盯idy发现的题,之前想学然后放弃了,于是今天几乎写了一天。有种紧迫感啊。然后发现好多认识的人都是最近过的。

 

思路比较简单,树上莫队。因为要修改,所以要把块的大小变成n2/3,然后用1086的方法分块。好像也可以直接按dfs序分块。两个端点和时间为三个关键字跑莫队。复杂度可以感受一下反正我也不会证。

 

要注意千万要控制LCA的用量,必需只能是O(n)级别的。在爬树的时候必需O(1)。我就是在移动时间的时候不小心手贱每次用一遍LCA,然后去检查在移动端点花了好久的时间。

 

比较不开心的是发现mac没法改栈空间?有两个点始终暴栈。而且拿另一台电脑的openSUSE跑,结果发现它的cpu没有mac好,跑得还比mac快!我猜是操作系统在捣鬼。mac还是比较坑啊不开心。然后在bzoj上跑的时间几乎是本地的5倍也是比较厉害啊。

 

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

using namespace std;

const int maxn = 100009;
const int maxl = 19;

typedef struct node {
	int t;
	node *next;
} edge;
node nlst[maxn], *np(nlst);
struct chain {
	int sz;
	node *hd, *tl;
	chain() {
		hd = tl = 0;
		sz = 0;
	}
	inline void clear() {
		hd = tl = 0;
		sz = 0;
	}
	inline void push(int x) {
		np-> t = x;
		np-> next = 0;
		if (sz) {
			tl-> next = np;
			tl = np;
		}
		else {
			hd = np;
			tl = np;
		}
		++ np;
		++ sz;
	}
	inline void merge(chain a) {
		sz += a. sz;
		if (a. sz) {
			if (hd) {
				tl-> next = a. hd;
				tl = a. tl;
			}
			else {
				hd = a. hd;
				tl = a. tl;
			}
		}
	}
};
struct query {
	int a, b, i, pa, pb, pi;
};
inline bool operator <(const query& a, const query& b) {
	return (a. pa < b. pa) || (a. pa == b. pa && a. pb < b. pb) || (a. pa == b. pa && a. pb == b. pb && a. i < b. i);
}

typedef long long dint;
#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif

int n, m, q, tq, tc, ty[maxn], fb[maxn], tb, bsz;
int d[maxn], ath[maxn][maxl];
bool oc[maxn];
dint w[maxn], v[maxn], ans[maxn], cnt[maxn];
edge elst[maxn << 1], *ep(elst), *head[maxn];
query qr[maxn], cg[maxn];

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

chain dfs(int p) {
	chain w;
	for (int i = 1; i < maxl; ++ i)
		ath[p][i] = ath[ath[p][i - 1]][i - 1];
	for (edge* e = head[p]; e; e = e-> next)
		if (!d[e-> t]) {
			d[e-> t] = d[p] + 1;
			ath[e-> t][0] = p;
			chain g(dfs(e-> t));
			w. merge(g);
			if (w. sz >= bsz) {
				++ tb;
				for (node* it = w. hd; it; it = it-> next)
					fb[it-> t] = tb;
				w. clear();
			}
		}
	w. push(p);
	return w;
}
void divide() {
	memset(d, 0, sizeof(d));
	tb = 0;
	d[1] = 1;
	chain g(dfs(1));
	for (node* it = g. hd; it; it = it-> next)
		fb[it-> t] = tb;
}

int LCA(int u, int v) {
	if (d[u] < d[v])
		swap(u, v);
	for (int i = maxl - 1; i >= 0; -- i)
		if (d[ath[u][i]] >= d[v])
			u = ath[u][i];
	if (u == v)
		return u;
	for (int i = maxl - 1; i >= 0; -- i)
		if (ath[u][i] ^ ath[v][i]) {
			u = ath[u][i];
			v = ath[v][i];
		}
	return ath[u][0];
}
bool onChain(int u, int v, int p) {
	if (p == u || p == v)
		return 1;
	int a(LCA(u, v));
	if (p == a)
		return 1;
	if (LCA(p, a) != a)
		return 0;
	else
		return LCA(p, u) == p || LCA(p, v) == p;
}

inline void rmVertex(int p, dint& ans) {
	if (oc[p]) {
		ans -= w[cnt[ty[p]]] * v[ty[p]];
		-- cnt[ty[p]];
		ans += w[cnt[ty[p]]] * v[ty[p]];
		oc[p] = 0;
	}
}
inline void insVertex(int p, dint& ans) {
	if (!oc[p]) {
		ans -= w[cnt[ty[p]]] * v[ty[p]];
		++ cnt[ty[p]];
		ans += w[cnt[ty[p]]] * v[ty[p]];
		oc[p] = 1;
	}
}
void moveVertex(int& u, int v, int g, dint& ans) {
	int p(u), q(g), a(LCA(u, v)), t(LCA(a, g));
	if (t == a) {
		int x(LCA(u, g)), y(LCA(v, g));
		if (d[x] > d[y])
			t = x;
		else
			t = y;
		if (LCA(u, t) == t) {
			for (; q ^ t; q = ath[q][0])
				insVertex(q, ans);
			for (; p ^ t; p = ath[p][0])
				rmVertex(p, ans);
		}
		else {
			for (; q ^ t; q = ath[q][0])
				insVertex(q, ans);
			for (; p ^ a; p = ath[p][0])
				rmVertex(p, ans);
			rmVertex(a, ans);
			for (q = ath[t][0]; q ^ a; q = ath[q][0])
				rmVertex(q, ans);
		}
	}
	else {
		for (; p ^ a; p = ath[p][0])
			rmVertex(p, ans);
		for (p = ath[a][0]; p ^ t; p = ath[p][0])
			insVertex(p, ans);
		for (; q ^ t; q = ath[q][0])
			insVertex(q, ans);
		insVertex(t, ans);
	}
	u = g;
}

inline void chgType(int p, int tn, dint& ans) {
	if (oc[p]) {
		ans -= :: v[ty[p]] * w[cnt[ty[p]]];
		-- cnt[ty[p]];
		ans += :: v[ty[p]] * w[cnt[ty[p]]];
		ty[p] = tn;
		ans -= :: v[ty[p]] * w[cnt[ty[p]]];
		++ cnt[ty[p]];
		ans += :: v[ty[p]] * w[cnt[ty[p]]];
	}
	else {
		ty[p] = tn;
	}
}
void moveChgTime(int& t, int g, dint& ans) {
	for (; t + 1 < tc && cg[t + 1]. i < g; ++ t)
		chgType(cg[t + 1]. a, cg[t + 1]. b, ans);
	for (; t > -1 && cg[t]. i > g; -- t)
		chgType(cg[t]. a, cg[t]. pb, ans);
}

void cptMo() {
	memset(ans, -1, sizeof(ans));
	sort(qr, qr + tq);
	int u(1), v(1), t(-1);
	dint cans(:: v[ty[1]] * w[1]);
	memset(cnt, 0, sizeof(cnt));
	memset(oc, 0, sizeof(oc));
	oc[1] = 1;
	cnt[ty[1]] = 1;
	for (int i = 0; i < tq; ++ i) {
		moveVertex(u, v, qr[i]. a, cans);
		moveVertex(v, u, qr[i]. b, cans);
		moveChgTime(t, qr[i]. i, cans);
		ans[qr[i]. i] = cans;
	}
}

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

	scanf("%d%d%d", &n, &m, &q);
	bsz = (int)pow(n, 0.66) + 1;
	for (int i = 1; i <= m; ++ i)
		scanf(lld, v + i);
	w[0] = 0;
	for (int i = 1; i <= n; ++ i) {
		scanf(lld, w + i);
		w[i] += w[i - 1];
	}
	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);
	}
	for (int i = 1; i <= n; ++ i)
		scanf("%d", ty + i);
	divide();
	tc = tq = 0;
	for (int i = 0; i < q; ++ i) {
		int t, a, b;
		scanf("%d%d%d", &t, &a, &b);
		if (!t) {
			cg[tc]. i = i;
			cg[tc]. a = a;
			cg[tc]. b = b
			cg[tc]. pb = ty[a];
			ty[a] = b;
			++ tc;
		}
		else {
			if (a > b)
				swap(a, b);
			qr[tq]. i = i;
			qr[tq]. pi = i / bsz;
			qr[tq]. a = a;
			qr[tq]. pa = fb[a];
			qr[tq]. b = b;
			qr[tq]. pb = fb[b];
			++ tq;
		}
	}
	for (int i = tc - 1; i >= 0; -- i)
		ty[cg[i]. a] = cg[i]. pb;
	cptMo();
	for (int i = 0; i < q; ++ i)
		if (ans[i] > -1)
			printf(lld "\n", ans[i]);
}

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);
		}
	}
}

BZOJ1453 [Wc]Dface双面棋盘

有离线镜像还是能省不少流量。开心。不过流量还是用得飞快啊。

 

这就是个cdq重构的题。学习了前几天xyz大爷讲的扔线段树的做法,省了不少代码。

 

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

using namespace std;

struct node {
	int v, c;
	node *next;
};
struct seg {
	int l, r;
	node *head;
	seg *ls, *rs;
};

const int maxa = 209;
const int maxn = 40009;
const int maxm = 10009;
const int maxnd = maxn * 23;
const int mov[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};

#define upmax(_a_,_b_) { \
	if (_a_ < _b_) \
		_a_ = _b_; \
}
#define mkpos(_x_,_y_) (((_x_)<<16)|(_y_))
#define getx(_a_) ((_a_)>>16)
#define gety(_a_) ((_a_)&0x0000ffff)
#define nid(_x_,_y_) (((_x_)*n)+(_y_))

struct disjoint_set {
	int r[maxn], h[maxn];
	int vst[maxn], rst[maxn], ust[maxn], hst[maxn], tst;
	inline disjoint_set() {
		tst = 0;
	}
	void init(int n) {
		for (int i = 0; i < n; ++ i)
			r[i] = i, h[i] = 1;
	}
	int getRoot(int x) {
		for (; r[x] ^ x; x = r[x]);
		return x;
	}
	inline void merge(int u, int v) {
		u = getRoot(u), v = getRoot(v);
		if (h[u] < h[v])
			swap(u, v);
		vst[++ tst] = v;
		rst[tst] = r[v];
		r[v] = u;
		ust[tst] = u;
		hst[tst] = h[u];
		upmax(h[u], h[v] + 1);
	}
	void recover(int x) {
		while (tst > x) {
			r[vst[tst]] = rst[tst];
			h[vst[tst]] = hst[tst];
			-- tst;
		}
	}
};

node nlst[maxnd], *np(nlst);
seg slst[maxn * 3], *sp(slst), *rt;
int n, m, a[maxa][maxa], cc[maxa][maxa], pret[maxa][maxa], ansb[maxm], answ[maxm];

#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-> head = 0;
	if (l + 1 < r) {
		p-> ls = sgtBuild(l, midp(p));
		p-> rs = sgtBuild(midp(p), r);
	}
	return p;
}
inline void sgtIns(seg* p, int l, int r, int ps, int cl) {
	if (p-> l == l && p-> r == r) {
		np-> v = ps;
		np-> c = cl;
		np-> next = p-> head;
		p-> head = np ++;
	}
	else if (r <= midp(p))
		sgtIns(p-> ls, l, r, ps, cl);
	else if (l >= midp(p))
		sgtIns(p-> rs, l, r, ps, cl);
	else {
		sgtIns(p-> ls, l, midp(p), ps, cl);
		sgtIns(p-> rs, midp(p), r, ps, cl);
	}
}

disjoint_set r;

void sgtDfs(seg* p, int cb, int cw) {
	int rp(r. tst);
	for (node* it = p-> head; it; it = it-> next) {
		int x(getx(it-> v)), y(gety(it-> v)), c(it-> c), *v;
		if (c == 0)
			v = &cw;
		else
			v = &cb;
		++ *v;
		cc[x][y] = c;
		for (int mi = 0; mi < 4; ++ mi) {
			int x1(x + mov[mi][0]), y1(y + mov[mi][1]);
			if (x1 < 0 || x1 >= n || y1 < 0 || y1 >= n)
				continue;
			if (cc[x1][y1] == c && r. getRoot(nid(x, y)) != r. getRoot(nid(x1, y1))) {
				-- *v;
				r. merge(nid(x, y), nid(x1, y1));
			}
		}
	}
	if (p-> l + 1 == p-> r) {
		ansb[p-> l] = cb;
		answ[p-> l] = cw;
	}
	else {
		sgtDfs(p-> ls, cb, cw);
		sgtDfs(p-> rs, cb, cw);
	}
	for (node* it = p-> head; it; it = it-> next) {
		int x(getx(it-> v)), y(gety(it-> v));
		cc[x][y] = -1;
	}
	r. recover(rp);
}

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

	scanf("%d", &n);
	for (int i = 0; i < n; ++ i)
		for (int j = 0; j < n; ++ j) {
			scanf("%d", a[i] + j); 
			pret[i][j] = 0;
		}
	scanf("%d", &m);
	rt = sgtBuild(0, m + 1);
	for (int i = 1; i <= m; ++ i) {
		int x, y;
		scanf("%d%d", &x, &y);
		-- x;
		-- y;
		sgtIns(rt, pret[x][y], i, mkpos(x, y), a[x][y]);
		a[x][y] ^= 1;
		pret[x][y] = i;
	}
	for (int i = 0; i < n; ++ i)
		for (int j = 0; j < n; ++ j)
			sgtIns(rt, pret[i][j], m + 1, mkpos(i, j), a[i][j]);
	memset(cc, 0, sizeof(cc));
	r. init(n * n);
	memset(cc, -1, sizeof(cc));
	sgtDfs(rt, 0, 0);
	for (int i = 1; i <= m; ++ i)
		printf("%d %d\n", ansb[i], answ[i]);
}

HDU5173 GTY's game II

bc的题。今天bc又挂了。这题没有写完,然后b题fst了。伤心啊。

 

其实思路比较简单。直接链剖dfs序上把所有区间找出来swap就好了。不过代码实现起来还是比较麻烦的,很容易绕晕。加上smt久了没写手生了,于是就调了一晚上。唉,我还是太年轻了。

 

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

using namespace std;

struct node {
	int v, s, sz, w, rv;
	node *ls, *rs;
	inline void update() {
		sz = 1;
		s = v;
		if (ls) {
			sz += ls-> sz;
			s += ls-> s;
		}
		if (rs) {
			sz += rs-> sz;
			s += rs-> s;
		}
	}
	inline void fix() {
		if (rv) {
			swap(ls, rs);
			if (ls)
				ls-> rv ^= 1;
			if (rs)
				rs-> rv ^= 1;
			rv = 0;
		}
	}
};
typedef pair <node*, node*> npr;

const int maxn = 80009;

#define szof(p) ((p)?(p->sz):0)
#define sof(p) ((p)?(p->s):0)
node nlst[maxn << 1], *np(nlst);
node* newNode(int v) {
	np-> ls = np-> rs = 0;
	np-> v = np-> s = v;
	np-> sz = 1;
	np-> rv = 0;
#ifdef WIN32
	np-> w = (rand() << 16) | rand();
#else
	np-> w = rand();
#endif
	return np ++;
}
node* merge(node* p, node* q) {
	if (p)
		p-> fix();
	else
		return q;
	if (q)
		q-> fix();
	else
		return p;
	if (p-> w > q-> w) {
		p-> rs = merge(p-> rs, q);
		p-> update();
		return p;
	}
	else {
		q-> ls = merge(p, q-> ls);
		q-> update();
		return q;
	}
}
npr split(node* p, int k) {
	if (!k)
		return npr(0, p);
	else if (!p || p-> sz == k)
		return npr(p, 0);
	else {
		p-> fix();
		if (k <= szof(p-> ls)) {
			npr g(split(p-> ls, k));
			p-> ls = g. second;
			p-> update();
			return npr(g. first, p);
		}
		else {
			npr g(split(p-> rs, k - szof(p-> ls) - 1));
			p-> rs = g. first;
			p-> update();
			return npr(p, g. second);
		}
	}
}
int smtQry(node* p, int k) {
	int s(0);
	while (p && k) {
		p-> fix();
		if (k <= szof(p-> ls))
			p = p-> ls;
		else
			s += sof(p-> ls) + p-> v, k -= szof(p-> ls) + 1, p = p-> rs;
	}
	return s;
}

struct edge {
	int t;
	edge *next;
};
edge *head[maxn], elst[maxn << 1], *ep(elst);
inline void addEdge(int u, int v) {
	ep-> t = v;
	ep-> next = head[u];
	head[u] = ep ++;
}

int v[maxn], n, m;
int tc, fa[maxn], d[maxn], sz[maxn], fs[maxn], fc[maxn], ch[maxn];
int dfb[maxn], dfo[maxn];
node *rt, *remp;

void divide() {
	static int stc[maxn];
	int tst(1), dfn(0);
	memset(fa, 0, sizeof(fa));
	stc[tst] = 1;
	while (tst) {
		int p(stc[tst --]);
		dfo[++ dfn] = p;
		for (edge* e = head[p]; e; e = e-> next)
			if (e-> t ^ fa[p]) {
				fa[e-> t] = p;
				d[e-> t] = d[p] + 1;
				stc[++ tst] = e-> t;
			}
	}
	tc = 0;
	for (int i = n; i; -- i) {
		int p(dfo[i]);
		fs[p] = -1;
		sz[p] = 1;
		for (edge* e = head[p]; e; e = e-> next)
			if (fa[e-> t] == p) {
				sz[p] += sz[e-> t];
				if (fs[p] == -1 || sz[e-> t] > sz[fs[p]])
					fs[p] = e-> t;
			}
		if (fs[p] == -1)
			fc[p] = ++ tc;
		else
			fc[p] = fc[fs[p]];
		ch[fc[p]] = p;
	}
	stc[tst = 1] = 1;
	dfn = 0;
	while (tst) {
		int p(stc[tst --]);
		dfo[++ dfn] = p;
		dfb[p] = dfn;
		for (edge* e = head[p]; e; e = e-> next)
			if (fa[e-> t] == p && e-> t != fs[p])
				stc[++ tst] = e-> t;
		if (fs[p] != -1)
			stc[++ tst] = fs[p];
	}
	rt = 0;
	for (int i = 1; i <= n; ++ i)
		rt = merge(rt, newNode(v[dfo[i]]));
	remp = 0;
	for (int i = 1; i <= n; ++ i)
		remp = merge(remp, newNode(-1));
}

int query(int u, int v) {
	int s(0);
	while (fc[u] ^ fc[v])
		if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
			s += smtQry(rt, dfb[u]) - smtQry(rt, dfb[ch[fc[u]]] - 1);
			u = fa[ch[fc[u]]];
		}
		else {
			s += smtQry(rt, dfb[v]) - smtQry(rt, dfb[ch[fc[v]]] - 1);
			v = fa[ch[fc[v]]];
		}
	if (d[u] < d[v])
		s += smtQry(rt, dfb[v]) - smtQry(rt, dfb[u] - 1);
	else
		s += smtQry(rt, dfb[u]) - smtQry(rt, dfb[v] - 1);
	return s;
}

bool checkTree(node* p, char e) {
	if (p) {
		if (p-> rv) {
			checkTree(p-> rs, 32);
			printf("%d%c", p-> v, e);
			checkTree(p-> ls, 32);
		}
		else {
			checkTree(p-> ls, 32);
			printf("%d%c", p-> v, e);
			checkTree(p-> rs, 32);
		}
	}
	return 0;
}

typedef pair <int, int> rpr;
rpr ra[maxn], rb[maxn];
void flip(int u, int v) {
	int tra(0), trb(0);
	while (fc[u] ^ fc[v]) {
		if (d[ch[fc[u]]] > d[ch[fc[v]]]) {
			ra[tra ++] = rpr(dfb[ch[fc[u]]], dfb[u]);
			u = fa[ch[fc[u]]];
		}
		else {
			rb[trb ++] = rpr(dfb[ch[fc[v]]], dfb[v]);
			v = fa[ch[fc[v]]];
		}
	}
	if (d[u] < d[v])
		rb[trb ++] = rpr(dfb[u], dfb[v]);
	else
		ra[tra ++] = rpr(dfb[v], dfb[u]);
	node *cr(0);
	for (int i = 0; i < tra; ++ i) {
		npr x = split(rt, ra[i]. first - 1);
		npr y = split(x. second, ra[i]. second - ra[i]. first + 1);
		cr = merge(y. first, cr);
		npr z = split(remp, ra[i]. second - ra[i]. first + 1);
		remp = z. second;
		x. second = merge(z. first, y. second);
		rt = merge(x. first, x. second);
	}
	if (cr)
		cr-> rv ^= 1;
	for (int i = trb - 1; i >= 0; -- i) {
		npr x = split(rt, rb[i]. first - 1);
		npr y = split(x. second, rb[i]. second - rb[i]. first + 1);
		cr = merge(cr, y. first);
		npr z = split(remp, rb[i]. second - rb[i]. first + 1);
		remp = z. second;
		x. second = merge(z. first, y. second);
		rt = merge(x. first, x. second);
	}
	if (cr)
		cr-> rv ^= 1;
	for (int i = 0; i < tra; ++ i) {
		npr x = split(rt, ra[i]. first - 1);
		npr y = split(x. second, ra[i]. second - ra[i]. first + 1);
		npr z = split(cr, ra[i]. second - ra[i]. first + 1);
		cr = z. second;
		if (z. first)
			z. first-> rv ^= 1;
		x. second = merge(z. first, y. second);
		rt = merge(x. first, x. second);
		remp = merge(remp, y. first);
	}
	if (cr)
		cr-> rv ^= 1;
	for (int i = 0; i < trb; ++ i) {
		npr x = split(rt, rb[i]. first - 1);
		npr y = split(x. second, rb[i]. second - rb[i]. first + 1);
		npr z = split(cr, rb[i]. second - rb[i]. first + 1);
		cr = z. second;
		if (z. first)
			z. first-> rv ^= 1;
		x. second = merge(z. first, y. second);
		rt = merge(x. first, x. second);
		remp = merge(remp, y. first);
	}
}

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

	memset(head, 0, sizeof(head));
	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i)
		scanf("%d", v + i);
	for (int i = 1; i < n; ++ i) {
		int u, v;
		scanf("%d%d", &u, &v);
		addEdge(u, v);
		addEdge(v, u);
	}
	divide();
	while (m --) {
		int opt, u, v;
		scanf("%d%d%d", &opt, &u, &v);
		if (opt == 0)
			printf("%d\n", query(u, v));
		else
			flip(u, v);
	}
}

BZOJ3435 [Wc2014]紫荆花之恋

想起去年在考场上完全没有思路不想写数据结构于是骗了30分。现在想想当初还是naive。

 

这题看上去就是点分治。因为要动态加点所以要动态。然后利用替罪羊树的方法重构树上的一团东西(不能叫团,否则命名重复了)。

 

本来以为要写很久,结果也没写多久。奇怪的是,把maintain展开到insert里面之后就跑得飞快了,否则过不到而且根本跑不下来9和10。又丑了郁闷。

 

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

using namespace std;

const int buf_len = 4000;
const size_t buf_size = buf_len * sizeof(char);
char buf[buf_len], *bufb(buf), *bufe(buf + 1);
#define readBuf() { \
	if (++ bufb == bufe) \
		bufe = (bufb = buf) + fread(buf, 1, buf_size, stdin); \
}
#define readInt(_x_) { \
	register int _s_(0); \
	do { \
		readBuf(); \
	} while (!isdigit(*bufb)); \
	do { \
		_s_ = _s_ * 10 + *bufb - 48; \
		readBuf(); \
	} while (isdigit(*bufb)); \
	_x_ = _s_; \
}

struct edge {
	int t, v;
	edge *next;
};
struct sbt_node {
	int vl, sz;
	sbt_node *ls, *rs;
};

typedef long long dint;

#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif
#define _l (long long int)

const int maxn = 100009;
const int fmod = 1e9;
const int maxl = 19;
const int maxnd = maxn * maxl * 2;
const int balc = 3;
const double ublim = 0.9;
const int inf = 0x3f3f3f3f;

dint lans;
int n;
int ath[maxn][maxl], drt[maxn], dep[maxn];
int bd[maxn], bsz[maxn], bfa[maxn], br[maxn], r[maxn];
int stsz[maxn], vis[maxn], vist;
sbt_node slst[maxnd], *sstc[maxnd], **sp, *brt[maxn], *prt[maxn];
edge *head[maxn], elst[maxn << 1], *ep(elst);

void pre() {
	for (int i = 0; i < maxnd; ++ i) {
		sstc[i] = slst + i;
		slst[i]. ls = slst[i]. rs = 0;
	}
	sp = sstc;
	vist = 0;
	memset(vis, 0, sizeof(vis));
}

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

#define szof(_p_) ((_p_)?(_p_->sz):0)
inline sbt_node* allocNode() {
	static sbt_node* ret;
	ret = *(sp ++);
	if (ret-> ls)
		*(-- sp) = ret-> ls;
	if (ret-> rs)
		*(-- sp) = ret-> rs;
	return ret;
}
inline void lRot(sbt_node* &p) {
	register sbt_node* q(p-> ls);
	p-> ls = q-> rs;
	q-> rs = p;
	q-> sz = p-> sz;
	p-> sz = szof(p-> ls) + szof(p-> rs) + 1;
	p = q;
}
inline void rRot(sbt_node* &p) {
	register sbt_node* q(p-> rs);
	p-> rs = q-> ls;
	q-> ls = p;
	q-> sz = p-> sz;
	p-> sz = szof(p-> ls) + szof(p-> rs) + 1;
	p = q;
}
inline void sbtIns(sbt_node* &p, int v0) {
	if (!p) {
		p = allocNode();
		p-> ls = p-> rs = 0;
		p-> sz = 1;
		p-> vl = v0;
	}
	else {
		++ p-> sz;
		if (v0 < p-> vl) {
			sbtIns(p-> ls, v0);
			if (szof(p-> ls) > szof(p-> rs) + balc)
				lRot(p);
		}
		else {
			sbtIns(p-> rs, v0);
			if (szof(p-> ls) + balc < szof(p-> rs))
				rRot(p);
		}
	}
}
int sbtCntLower(sbt_node* p, int v0) {
	int s(0);
	while (p)
		if (v0 < p-> vl)
			p = p-> ls;
		else
			s += szof(p-> ls) + 1, p = p-> rs;
	return s;
}

int LCA(int u, int v) {
	if (dep[u] < dep[v])
		swap(u, v);
	for (int i = maxl - 1; i >= 0; -- i)
		if (dep[ath[u][i]] >= dep[v])
			u = ath[u][i];
	if (u == v)
		return u;
	for (int i = maxl - 1; i >= 0; -- i)
		if (ath[u][i] ^ ath[v][i]) {
			u = ath[u][i];
			v = ath[v][i];
		}
	return ath[u][0];
}
inline int dist(int u, int v) {
	int a(LCA(u, v));
	return drt[u] + drt[v] - drt[a] * 2;
}

void insEach(sbt_node* q, sbt_node* &x, int mn) {
	static sbt_node* stc[maxn];
	int tst(1);
	stc[1] = q;
	while (tst) {
		sbt_node* p(stc[tst --]);
		sbtIns(x, p-> vl + mn);
				if (p-> ls)
			stc[++ tst] = p-> ls;
		if (p-> rs)
			stc[++ tst] = p-> rs;
	}
}
int build(int pbd, int pbr, int pbf) {
	static int q[maxn], fr[maxn], dst[maxn];
	int hd(0), tl(1), ct(0), cs(inf);
	q[0] = pbr;
	fr[pbr] = 0;
	dst[pbr] = 0;
	while (hd < tl) {
		int p(q[hd ++]);
		for (edge* e = head[p]; e; e = e-> next)
			if (bd[e-> t] == inf && e-> t != fr[p]) {
				fr[e-> t] = p;
				dst[e-> t] = dst[p] + e-> v;
				q[tl ++] = e-> t;
			}
	}
	for (int ti = tl - 1, p; ti >= 0; -- ti) {
		int ms(1);
		p = q[ti];
		stsz[p] = 1;
		for (edge* e = head[p]; e; e = e-> next)
			if (bd[e-> t] == inf && e-> t != fr[p]) {
				stsz[p] += stsz[e-> t];
				if (ms < stsz[e-> t])
					ms = stsz[e-> t];
			}
		if (ms < tl - stsz[p])
			ms = tl - stsz[p];
		if (ms < cs) {
			cs = ms;
			ct = p;
		}
	}
	for (int ti = 0, p; ti < tl; ++ ti) {
		p = q[ti];
		sbtIns(prt[ct], dst[p] - r[p]);
			}
	bd[ct] = pbd;
	bsz[ct] = tl;
	bfa[ct] = pbf;
	br[ct] = pbr;
	sbtIns(brt[ct], -r[ct]);
		for (edge* e = head[ct]; e; e = e-> next)
		if (bd[e-> t] == inf) {
			int nr(build(pbd + 1, e-> t, ct));
			insEach(prt[nr], brt[ct], e-> v);
		}
	return ct;
}

void rebuild(int p0, int pbd, int pbr, int pbf) {
	static int q[maxn];
	int hd(0), tl(1);
	++ vist;
	vis[p0] = vist;
	q[0] = p0;
	while (hd < tl) {
		int p(q[hd ++]);
		*(-- sp) = brt[p];
		*(-- sp) = prt[p];
		brt[p] = 0;
		prt[p] = 0;
		for (edge* e = head[p]; e; e = e-> next)
			if (bd[e-> t] > pbd && vis[e-> t] < vist) {
				vis[e-> t] = vist;
				q[tl ++] = e-> t;
			}
	}
	for (int i = 0; i < tl; ++ i)
		bd[q[i]] = inf;
	build(pbd, pbr, pbf);
}

void addNode(int p) {
	brt[p] = 0;
	sbtIns(brt[p], -r[p]);
		prt[p] = 0;
	sbtIns(prt[p], -r[p]);
		if (p == 1) {
		bd[p] = 1;
		bsz[p] = 1;
		bfa[p] = 0;
		br[p] = 1;
	}
	else {
		register int fa(ath[p][0]);
		bd[p] = bd[fa] + 1;
		bsz[p] = 1;
		bfa[p] = fa;
		br[p] = p;
		int q(fa), l(p), ubp, dt(0);
		double ubv(0);
		while (q) {
			++ bsz[q];
			if ((double)bsz[l] / bsz[q] > ubv) {
				ubv = (double)bsz[l] / bsz[q];
				ubp = q;
			}
			int d0(dist(p, q));
			sbtIns(brt[q], d0 - r[p]);
			sbtIns(prt[q], dist(br[q], p) - r[p]);
			dt += sbtCntLower(brt[q], r[p] - d0) - sbtCntLower(prt[l], r[p] - d0 - dist(br[l], q));
			l = q;
			q = bfa[q];
		}
		lans += dt;
		if (ubv > ublim)
			rebuild(ubp, bd[ubp], br[ubp], bfa[ubp]);
	}
}

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

	pre();
	readInt(n);
	readInt(n);
	lans = 0;
	for (int i = 1; i <= n; ++ i) {
		int fa;
		readInt(fa);
		readInt(drt[i]);
		readInt(r[i]);
		if (i > 1) {
			fa ^= lans % fmod;
			dep[i] = dep[fa] + 1;
			addEdge(fa, i, drt[i]);
			addEdge(i, fa, drt[i]);
			drt[i] += drt[fa];
			ath[i][0] = fa;
			for (int j = 1; j < maxl; ++ j)
				ath[i][j] = ath[ath[i][j - 1]][j - 1];
		}
		else {
			dep[i] = 1;
		}
		addNode(i);
		printf(lld "\n", lans);
	}
}

BZOJ2653 middle

老久之前就看到过的题,不过不会做。今天晚上也是花了差不多俩小时才调过,虽然大概一个半小时都在纠结二分怎么写的问题。我没救了。

 

考虑经典的中位数二分,是把≤x的数字取-1,>x的数取1,然后算最大子串看是否大于-1或1中的某一个,具体要看题目要求偶数是取上整还是下整什么的。

 

然后这题就把所有东西排序之后拿可持久化线段树把这个序列搞出来,然后照着之前的思路二分就好了。线段树用来维护最大和最小前缀和。

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

using namespace std;

struct dat {
	int sm, s;
};
struct seg {
	int l, r;
	dat v[2];
	seg *ls, *rs;
};

#define _l (long long int)

typedef pair <int, int> vpr;
typedef dat(*dat_mf)(const dat&, const dat&);

const int maxn = 20009;
const int maxnd = maxn * 19;
const dat null_str = {0, 0};
const dat neg_str0 = {-1, -1};
const dat neg_str1 = {-1, -1};
const dat pos_str0 = {1, 1};
const dat pos_str1 = {1, 1};

vpr a[maxn];
int n, m, q[4], lans, maxv;
seg slst[maxnd], *sp(slst), *rt[maxn];

#define mid(p) ((p->l+p->r)>>1)

dat ret;
inline dat merd0(const dat& a, const dat& b) {
	ret. sm = a. sm + b. sm;
	ret. s = min(a. s, a. sm + b. s);
	return ret;
}
inline dat merd1(const dat& a, const dat& b) {
	ret. sm = a. sm + b. sm;
	ret. s = max(a. s, a. sm + b. s);
	return ret;
}
const dat_mf dmf[2] = {merd0, merd1};
inline dat addSum(const int& v, const dat& a) {
	ret. s = a. s + v;
	ret. sm = a. sm + v;
	return ret;
}

seg* sgtBuild(int l, int r) {
	seg *p(sp ++);
	p-> l = l;
	p-> r = r;
	if (l + 1 == r) {
		p-> v[0] = neg_str0;
		p-> v[1] = neg_str1;
	}
	else {
		p-> ls = sgtBuild(l, mid(p));
		p-> rs = sgtBuild(mid(p), r);
		p-> v[0] = merd0(p-> ls-> v[0], p-> rs-> v[0]);
		p-> v[1] = merd1(p-> ls-> v[1], p-> rs-> v[1]);
	}
	return p;
}

seg* sgtChg(seg* q, int p0) {
	seg* p(sp ++);
	p-> l = q-> l;
	p-> r = q-> r;
	if (p-> l + 1 == p-> r) {
		p-> v[0] = pos_str0;
		p-> v[1] = pos_str1;
	}
	else {
		if (p0 < mid(p)) {
			p-> ls = sgtChg(q-> ls, p0);
			p-> rs = q-> rs;
		}
		else {
			p-> ls = q-> ls;
			p-> rs = sgtChg(q-> rs, p0);
		}
		p-> v[0] = merd0(p-> ls-> v[0], p-> rs-> v[0]);
		p-> v[1] = merd1(p-> ls-> v[1], p-> rs-> v[1]);
	}
	return p;
}

int qv;
dat sgtQry(seg* p, int l, int r) {
	if (p-> l == l && p-> r == r)
		return p-> v[qv];
	else if (r <= mid(p))
		return sgtQry(p-> ls, l, r);
	else if (l >= mid(p))
		return addSum(p-> ls-> v[0]. sm, sgtQry(p-> rs, l, r));
	else
		return dmf[qv](sgtQry(p-> ls, l, mid(p)), sgtQry(p-> rs, mid(p), r));
}

void pstat(seg* p, bool sr = 1) {
	if (p-> l + 1 == p-> r)
		printf("%d ", p-> v[0]. sm);
	else {
		pstat(p-> ls, 0);
		pstat(p-> rs, 0);
	}
	if (sr)
		putchar(10);
}

int minSum(int x) {
	int v0, v1;
	qv = 1;
	if (q[0] == 0)
		v0 = max(0, sgtQry(rt[x], 0, q[1]). s);
	else
		v0 = sgtQry(rt[x], q[0] - 1, q[1]). s;
	qv = 0;
	v1 = sgtQry(rt[x], q[2], q[3] + 1). s;
	return v1 - v0;
}

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

	scanf("%d", &n);
	for (int i = 0; i < n; ++ i)
		scanf("%d", &a[i]. first), a[i]. second = i;
	sort(a, a + n);
	rt[0] = sgtBuild(0, n);
	for (int i = 1; i <= n; ++ i)
		rt[i] = sgtChg(rt[i - 1], a[i - 1]. second);
	scanf("%d", &m);
	lans = 0;
	while (m --) {
		for (int i = 0; i < 4; ++ i) {
			scanf("%d", q + i); 
			q[i] = (_l q[i] + lans) % n;
		}
		sort(q, q + 4);
		int l(0), r(n - 1);
		while (l < r) {
			int md((l + r + 1) >> 1);
			if (minSum(md) > 0)
				r = md - 1;
			else
				l = md;
		}
		printf("%d\n", (lans = a[l]. first));
	}
}

BZOJ3351 [ioi2009]Regions

ioi的数据结构题,果然还是比较BT的。

 

做法是对颜色分开,大的颜色预处理,小的颜色直接暴力。

 

然后一个小错又坑了好久。我真的没救了。

#include <cstdio>
#include <cstdlib>
#include <cctype>
#include <cstring>
#include <algorithm>

using namespace std;

const int buf_len = 4000;
const size_t buf_size = buf_len * sizeof(char);
char buf[buf_len], *bufb(buf), *bufe(buf + 1);
#define readBuf() { \
	if (++ bufb == bufe) \
		bufe = (bufb = buf) + fread(buf, 1, buf_size, stdin); \
}
#define readInt(_x_) { \
	register int _s_(0); \
	do { \
		readBuf(); \
	} while (!isdigit(*bufb)); \
	do { \
		_s_ = _s_ * 10 + *bufb - 48; \
		readBuf(); \
	} while (isdigit(*bufb)); \
	_x_ = _s_; \
}

struct edge {
	int t;
	edge *next;
};
typedef pair <int, int> ninfo;
typedef long long dint;

#ifdef WIN32
#define lld "%I64d"
#else
#define lld "%lld"
#endif

const int maxn = 200009;
const int maxb = 259;
const int maxbn = 800;
const int maxc = 25009;

int n, r, q, c[maxn], bi[maxc], bc[maxn], nod[maxn];
int dfb[maxn], dfe[maxn], dfo[maxn];
dint bn[maxb][maxc], nb[maxb][maxc];
edge *head[maxn], elst[maxn], *ep(elst);
ninfo ni[maxn], ci[maxn];

struct bin_tree {
	int a[maxn], t[maxn], c;
	bin_tree() {
		c = 0;
		memset(t, 0, sizeof(t));
	}
	void chg(int p, int v) {
		for (; p <= n; p += (p & -p))
			if (t[p] < c)
				t[p] = c, a[p] = v;
			else
				a[p] += v;
	}
	int qry(int p) {
		int s(0);
		for (; p; p -= (p & -p))
			if (t[p] == c)
				s += a[p];
		return s;
	}
};

bin_tree bt;

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

void buildTree() {
	static int stc[maxn];
	int tst(1), dfn(0);
	stc[1] = 1;
	while (tst) {
		int p(stc[tst --]);
		dfo[dfb[p] = dfe[p] = ++ dfn] = p;
		for (edge* e = head[p]; e; e = e-> next)
			stc[++ tst] = e-> t;
	}
	for (int ti = n; ti; -- ti) {
		int p(dfo[ti]);
		for (edge* e = head[p]; e; e = e-> next)
			if (dfe[e-> t] > dfe[p])
				dfe[p] = dfe[e-> t];
	}
}

void preAns() {	
	static int ca[maxn], cb[maxn];
	memset(bn, 0, sizeof(bn));
	memset(nb, 0, sizeof(nb));
	for (int i = 1; i <= n; ++ i)
		ni[i - 1] = ninfo(c[i], i);
	sort(ni, ni + n);
	memset(cb, 0, sizeof(cb));
	memset(bi, -1, sizeof(bi));
	int tb(0);
	for (int i = 0, j; i < n; i = j) {
		for (j = i; j < n && ni[j]. first == ni[i]. first; ++ j)
			nod[j] = ni[j]. second;
		bc[ni[i]. first] = i;
		ci[tb ++] = ninfo(i - j, ni[i] .first);
	}
	sort(ci, ci + tb);
	for (int ti = 0; ti < tb && ti < maxb; ++ ti) {
		int i(bc[ci[ti]. second]), j(i - ci[ti]. first);
		bi[ni[i]. first] = ti;
		memset(ca, 0, sizeof(ca));
		memset(cb, 0, sizeof(cb));
		for (int k = i; k < j; ++ k) {
			++ ca[dfb[nod[k]]];
			++ cb[dfb[nod[k]]];
			-- cb[dfe[nod[k]] + 1];
		}
		for (int k = 1; k <= n; ++ k)
			ca[k] += ca[k - 1], cb[k] += cb[k - 1];
		for (int p = 1; p <= n; ++ p) {
			nb[ti][c[p]] += ca[dfe[p]] - ca[dfb[p] - 1];
			bn[ti][c[p]] += cb[dfb[p]];
		}
	}
}

dint query(int r1, int r2) {
	dint ans(0);
	++ bt. c;
	for (int i = bc[r2]; i < n && c[nod[i]] == r2; ++ i)
		bt. chg(dfb[nod[i]], 1);
	for (int i = bc[r1]; i < n && c[nod[i]] == r1; ++ i)
		ans += bt. qry(dfe[nod[i]]) - bt. qry(dfb[nod[i]] - 1);
	return ans;
}

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

	readInt(n);
	readInt(r);
	readInt(q);
	readInt(c[1]);
	memset(head, 0, sizeof(head));
	for (int i = 2; i <= n; ++ i) {
		int u;
		readInt(u);
		readInt(c[i]);
		addEdge(u, i);
	}
	buildTree();
	preAns();
	while (q --) {
		int r1, r2;
		readInt(r1);
		readInt(r2);
		if (bi[r1] > -1)
			printf(lld "\n", bn[bi[r1]][r2]);
		else if (bi[r2] > -1)
			printf(lld "\n", nb[bi[r2]][r1]);
		else
			printf(lld "\n", query(r1, r2));
	}
}

BZOJ2816 [ZJOI2012]网络

听说是水水的splay,果然是。

 

乍一看要用lct,然后因为度数只有2,所以肯定是一条链。然后就直接用splay来维护。然后因为少写了句splay(v)导致多调了至少一节课的时间。我没救了。

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

using namespace std;

#define upmax(_a_,_b_) { \
	if (_a_ < _b_) \
		_a_ = _b_; \
}

struct splay_node {
	int vl, vm, rv;
	splay_node *pt, *ls, *rs;
	inline void update() {
		vm = vl;
		if (ls)
			upmax(vm, ls-> vm);
		if (rs)
			upmax(vm, rs-> vm);
	}
	inline void fix() {
		if (rv) {
			swap(ls, rs);
			if (ls)
				ls-> rv ^= 1;
			if (rs)
				rs-> rv ^= 1;
			rv = 0;
		}
	}
};

typedef pair <int, int> edge;
typedef pair <edge, int> mpr;
typedef map <edge, int> emap;

const int maxn = 200009;
const int maxc = 13;

#define nid(_p_,_c_) ((_p_)+(_c_)*n)
#define eid(_e_) ((_e_)+eb)

splay_node slst[maxn], *sr[maxn];
int v[maxn], n, m, c, q, eb, nc[maxn][maxc], ce[maxn];
emap el;

inline void rot(splay_node* q) {
	splay_node *p(q-> pt), *a(p-> pt);
	if (a) {
		if (p == a-> ls) 
			a-> ls = q; 
		else 
			a-> rs = q; 
	}
	p-> pt = q;
	q-> pt = a;
	if (q == p-> ls) {
		if (q-> rs)
			q-> rs-> pt = p;
		p-> ls = q-> rs;
		q-> rs = p;
	}
	else {
		if (q-> ls)
			q-> ls-> pt = p;
		p-> rs = q-> ls;
		q-> ls = p;
	}
	p-> update();
	q-> update();
}

void splay(splay_node* q) {
	static splay_node* stc[maxn];
	int tst(1);
	stc[tst] = q;
	for (splay_node* p = q; p-> pt; p = p-> pt)
		stc[++ tst] = p-> pt;
	for (; tst; -- tst)
		stc[tst]-> fix();
	while (q-> pt) {
		splay_node *p(q-> pt);
		if (!p-> pt || !p-> pt-> pt)
			rot(q);
		else {
			if ((q == p-> ls) == (p == p-> pt-> ls)) {
				rot(p);
				rot(q);
			}
			else {
				rot(q);
				rot(q);
			}
		}
	}
}

splay_node* expose(splay_node* p) {
	splay(p);
	while (p) {
		p-> fix();
		if (p-> ls)
			p = p-> ls;
		else
			break;
	}
	return p;
}

void link(int e0, int u0, int v0) {
	splay_node *e(sr[e0]), *u(sr[u0]), *v(sr[v0]);
	splay(u);
	if (u-> fix(), u-> rs)
		u-> rv ^= 1;
	splay(v);
	if (v-> fix(), v-> ls)
		v-> rv ^= 1;
	e-> rv = 0;
	e-> ls = u;
	u-> pt = e;
	e-> rs = v;
	v-> pt = e;
	e-> update();
}

void cut(int e0) {
	splay_node* e(sr[e0]);
	splay(e);
	e-> fix();
	if (e-> ls) {
		e-> ls-> pt = 0;
		e-> ls = 0;
	}
	if (e-> rs) {
		e-> rs-> pt = 0;
		e-> rs = 0;
	}
	e-> update();
}

int query(int u0, int v0) {
	splay_node *u(sr[u0]), *v(sr[v0]);
	if (expose(u) != expose(v))
		return -1;
	if (u == v)
		return u-> vl;
	int ans(max(u-> vl, v-> vl));
	splay(u);
	splay(v);
	if (u == v-> ls) {
		if (u-> rs)
			upmax(ans, u-> rs-> vm);
	}
	else if (u == v-> rs) {
		if (u-> ls)
			upmax(ans, u-> ls-> vm);
	}
	return ans;
}

int main() {
	scanf("%d%d%d%d", &n, &m, &c, &q);
	eb = n * c;
	for (int i = 1; i <= eb + m; ++ i)
		sr[i] = slst + i;
	for (int i = 1; i <= n; ++ i) {
		scanf("%d", v + i);
		for (int j = 0; j < c; ++ j) {
			splay_node* p(sr[nid(i, j)]);
			p-> vl = p-> vm = v[i];
		}
	}
	for (int i = 1; i <= m; ++ i) {
		splay_node* p(sr[eid(i)]);
		p-> vl = p-> vm = 0;
		int u, v, w;
		scanf("%d%d%d", &u, &v, &w);
		link(eid(i), nid(u, w), nid(v, w));
		ce[i] = w;
		++ nc[u][w];
		++ nc[v][w];
		if (u > v)
			swap(u, v);
		el. insert(mpr(edge(u, v), i));
	}
	while (q --) {
		int opt, u, v, w;
		scanf("%d", &opt);
		if (opt == 0) {
			scanf("%d%d", &u, &v);
			for (int i = 0; i < c; ++ i) {
				splay_node* p(sr[nid(u, i)]);
				p-> vl = v;
				p-> update();
				splay(p);
			}
		}
		else if (opt == 1) {
			scanf("%d%d%d", &u, &v, &w);
			if (u > v)
				swap(u, v);
			emap :: iterator it = el. find(edge(u, v));
			if (it == el. end())
				puts("No such edge.");
			else if (w == ce[it-> second])
				puts("Success.");
			else if (nc[u][w] > 1 || nc[v][w] > 1)
				puts("Error 1.");
			else if (expose(sr[nid(u, w)]) == expose(sr[nid(v, w)]))
				puts("Error 2.");
			else {
				int e(it-> second);
				-- nc[u][ce[e]];
				-- nc[v][ce[e]];
				cut(eid(e));
				ce[e] = w;
				++ nc[u][ce[e]];
				++ nc[v][ce[e]];
				link(eid(e), nid(u, w), nid(v, w));
				puts("Success.");
			}
		}
		else {
			scanf("%d%d%d", &w, &u, &v);
			printf("%d\n", query(nid(u, w), nid(v, w)));
		}
	}
}

BZOJ2815 [ZJOI2012]灾难

灭绝树的模板题么。之前不知道这题,差点当原创题出出去了。

 

好像有不少人不知道这东西的样子?orz zhx。

 

灭绝树只有一句口诀:一个东西的父亲是所有入边的另一端的点的LCA。

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

using namespace std;

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

const int maxn = 70009;
const int maxl = 19;
const int maxe = 2000009;

int n, ind[maxn], oud[maxn], tpo[maxn], ath[maxn][maxl], sz[maxn], d[maxn];
edge *ha[maxn], *hr[maxn], *ht[maxn];

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

int LCA(int u, int v) {
	if (d[u] < d[v])
		swap(u, v);
	for (int i = maxl - 1; i >= 0; -- i)
		if (d[ath[u][i]] >= d[v])
			u = ath[u][i];
	if (u == v)
		return u;
	for (int i = maxl - 1; i >= 0; -- i)
		if (ath[u][i] ^ ath[v][i]) {
			u = ath[u][i];
			v = ath[v][i];
		}
	return ath[u][0];
}

void topSort() {
	static int q[maxn];
	int hd(0), tl(0);
	for (int i = 1; i <= n; ++ i)
		if (!ind[i])
			tpo[tl ++] = i;
	while (hd < tl) {
		int p(tpo[hd ++]);
		for (edge* e = ha[p]; e; e = e-> next) {
			-- ind[e-> t];
			if (!ind[e-> t])
				tpo[tl ++] = e-> t;
		}
	}
	d[0] = 0;
	for (int ti = 0; ti < n; ++ ti) {
		int p(tpo[ti]), a;
		if (!hr[p]) {
			a = 0;
		}
		else {
			a = hr[p]-> t;
			for (edge* e = hr[p]-> next; e; e = e-> next)
				a = LCA(a, e-> t);
		}
		addEdge(ht, a, p);
		ath[p][0] = a;
		for (int i = 1; i < maxl; ++ i)
			ath[p][i] = ath[ath[p][i - 1]][i - 1];
		d[p] = d[a] + 1;
	}
	for (int ti = n - 1; ti >= 0; -- ti) {
		int p(tpo[ti]);
		sz[p] = 1;
		for (edge* e = ht[p]; e; e = e-> next)
			sz[p] += sz[e-> t];
	}
}

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

	scanf("%d", &n);
	for (int i = 1; i <= n; ++ i) {
		int v;
		while (scanf("%d", &v), v) {
			addEdge(ha, v, i);
			addEdge(hr, i, v);
			++ oud[v];
			++ ind[i];
		}
	}
	topSort();
	for (int i = 1; i <= n; ++ i)
		printf("%d\n", sz[i] - 1);
}

BZOJ3251 树上三角形

原来在win下也有敲回车的bug。开心。

 

这题坑啊。暴力还是很好想的,如果个数超过几十个的话就肯定有解了。比较坑的是两边之和大于第三边,边权231-1然后加起来就超过int的范围了。连WA若干次再见。

 

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

using namespace std;

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

const int maxn = 100009;
const int maxc = 88;

int n, m, v[maxn], d[maxn], fa[maxn], c[maxc];
edge *head[maxn], elst[maxn << 1], *ep(elst);

void bfs() {
	static int q[maxn];
	int hd(0), tl(1);
	q[0] = 1;
	memset(d, 0, sizeof(d));
	d[1] = 1;
	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;
			}
	}
}

bool qry(int x, int y) {
	int t(0);
	while (t < 60 && x != y) {
		if (d[x] > d[y]) {
			c[t ++] = v[x];
			x = fa[x];
		}
		else {
			c[t ++] = v[y];
			y = fa[y];
		}
	}
	if (x == y)
		c[t ++] = v[x];
	else
		return 1;
	sort(c, c + t);
	for (int i = 2; i < t; ++ i)
		if (c[i] - c[i - 1] < c[i - 2])
			return 1;
	return 0;
}

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

	scanf("%d%d", &n, &m);
	for (int i = 1; i <= n; ++ i)
		scanf("%d", v + i);
	for (int i = 1; i < n; ++ i) {
		int u, v;
		scanf("%d%d", &u, &v);
		ep-> t = v;
		ep-> next = head[u];
		head[u] = ep ++;
		ep-> t = u;
		ep-> next = head[v];
		head[v] = ep ++;
	}
	bfs();
	while (m --) {
		int t, x, y;
		scanf("%d%d%d", &t, &x, &y);
		if (t == 0)
			puts(qry(x, y) ? "Y" : "N");
		else 
			v[x] = y;
	}
}

BZOJ3314 [Usaco2013 Nov]Crowded Cows

又搬blog。发现这里可以自定义css之后就果断了。

 

写道水题试试。set的应用。然后还写丑WA了两次,我没救了。

 

代码高亮是坏了吗?不要吓我。

 

决定直接用oj7的代码版了,没有高亮就算了。

#include <cstdio>
#include <algorithm>
#include <set>

using namespace std;

typedef multiset <int> rb_tree;
typedef rb_tree :: iterator rb_node;
typedef pair <int, int> cow;

const int maxn = 50009;

int n, d, x[maxn], a[maxn], r[maxn];
cow c[maxn];
rb_tree t;

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

	scanf("%d%d", &n, &d);
	for (int i = 1; i <= n; ++ i) {
		scanf("%d%d", x + i, a + i);
		c[i] = cow(x[i], a[i]);
		r[i] = 0;
	}
	sort(c + 1, c + n + 1);
	for (int i = 1; i <= n; ++ i) {
		x[i] = c[i]. first;
		a[i] = c[i]. second;
	}
	for (int i = 1, j = 1; i <= n; ++ i) {
		while (x[i] - x[j] > d) {
			t. erase(t. find(a[j]));
			++ j;
		}
		if (t. lower_bound(a[i] << 1) != t. end())
			++ r[i];
		t. insert(a[i]);
	}
	t. clear();
	int ans(0);
	for (int i = n, j = n; i; -- i) {
		while (x[j] - x[i] > d) {
			t. erase(t. find(a[j]));
			-- j;
		}
		if (t. lower_bound(a[i] << 1) != t. end())
			++ r[i];
		if (r[i] == 2)
			++ ans;
		t. insert(a[i]);
	}
	printf("%d\n", ans);
}