4-7考试总结

$$4-7$$

  • 第二题是密码锁就直接发出来了,第一题的话又写了一天
  • 自己垃圾,无话可说
  • 总结一下\(LCT\)简单的子树信息维护要怎么做,以维护子树大小为例,我们对每个子树维护两个信息,一个是子树总大小,一个是虚树的总大小,能够发现我们如果能够快速处理虚树的大小,问题就得到了解决;观察\(LCT\)什么时候会添加、减少虚儿子,\(access \ \ and \ \ link!\),所以在进行这两个操作的时候判断一下就可以了,但是注意这样只能维护可增减的信息,最大值我就完全不会
  • 这道题只需要有大小为\(K\)的联通块,考虑魔法森林的解法,一样从按照\(A\)小到大插入边,维护\(B\)的联通块,可以发现一个联通块有用的信息一定可以表示成一棵树(就是和魔法森林那题差不多),然后考虑能不能试着减少\(B\),如果当前有\(>=K\)的连通块这条最大边是一定没有意义的,因为此时更新的答案一定会比不删这条边的答案优,然后维护\(>=K\)连通块个数以及连通块大小就可以了
  • 吐槽:感觉学子树信息就学了半天看了,一中午哑舍下午头都是昏的加上\(LCT\)的代码好久没写又回忆了好久,下午调的时候一直不清醒,晚上状态反而好多了,xjb乱写也能调过,结果最后是\(push\_up\)的时候没注意重新赋初值,然后删边就爆炸了
  • 放个代码感慨一下吧
#include <bits/stdc++.h>

typedef std::pair<int, int> PII;

#define a first
#define b second

inline int read(int Num = 0, int Flag = 1)
{
	char ch = getchar();
	for (; !isdigit(ch); ch = getchar()) 
		if (ch == '-')
			Flag = -1;
	for (;  isdigit(ch); ch = getchar())
		Num = Num * 10 + ch - '0';
	return Num *= Flag;
}

template <typename T> bool chkmax(T &a, T b) { return a < b? a = b, true : false; }
template <typename T> bool chkmin(T &a, T b) { return a > b? a = b, true : false; }

const int mx_n = 3e5 + 5;
const int mx_m = 5e5 + 5;
const int inf = 2e9 + 5;

int N, M, K;
int a[mx_n], b[mx_n];

//int cur;
struct Edge
{
	int u, v, wa, wb;
	bool operator < (const Edge& rhs)const
	{
		return wa < rhs.wa;
	}
}edge[mx_m];

int tot;

struct Link_Cut_Tree
{
static const int mx_node = (mx_n + mx_m) * 2;

int fa[mx_node];
int ch[mx_node][2];

int isv[mx_node];
int sz_all[mx_node];
int sz_sub[mx_node];

int stk[mx_node];
int rev[mx_node];
PII maxb[mx_node];

inline int prefer(int x)
{
//	assert(!isrt(x));
	return ch[fa[x]][1] == x;
}

inline bool isrt(int x)
{
	return ch[fa[x]][0] != x && ch[fa[x]][1] != x;
}

inline void push_up(int h)
{
	sz_all[h] = (h <= N) + sz_sub[h];
	if (h > N) maxb[h] = PII(edge[h - N].wb, h - N);
	else maxb[h] = PII(0, 0);
	for (int i = 0; i < 2; ++i) {
		chkmax(maxb[h], maxb[ch[h][i]]);
		sz_all[h] += sz_all[ch[h][i]];
	}
}

inline void push_down(int h)
{
	if (rev[h]) {
		rev[ch[h][0]] ^= 1, rev[ch[h][1]] ^= 1;
		std::swap(ch[h][0], ch[h][1]);
		rev[h] = 0;
	}
}

void rotate(int x, int ty)
{
	int y = fa[x];
	if (!isrt(y)) ch[fa[y]][prefer(y)] = x; fa[x] = fa[y];
	ch[y][!ty] = ch[x][ty]; fa[ch[x][ty]] = y;
	ch[x][ty] = y; fa[y] = x;
	push_up(y);
	push_up(x);
}

void pass_tag(int u)
{
	int top = 0; stk[++top] = u;
	for (int i = u; !isrt(i); i = fa[i]) stk[++top] = fa[i];
	for (int i = top; i >= 1; --i) push_down(stk[i]);
}

void splay(int h)
{
	pass_tag(h);
	for (int ty; !isrt(h); rotate(h, !ty)) {
		ty = prefer(h);
		if (!isrt(fa[h]) && prefer(fa[h]) == ty) rotate(fa[h], !ty);
	}
}

void access(int u)
{
	for (int v = 0; u; v = u, u = fa[u]) {
		splay(u);
		sz_sub[u] += sz_all[ch[u][1]];
		sz_sub[u] -= sz_all[v];
		ch[u][1] = v; push_up(u);
	}
//	fprintf(stderr, "end\n");
}

void make_root(int u)
{
	access(u); splay(u), rev[u] ^= 1;
}

int find(int u)
{
	access(u); splay(u);
	for (; ch[u][0];) u = ch[u][0];
	splay(u);
	return u;
}

PII query(int u, int v)
{
	make_root(u); access(v), splay(v);
	return maxb[v];
}

void cut(int u, int v)
{
//	assert(find(u) == find(v));
	make_root(u);
	access(v);
	splay(v);
//	if (cur == 6) fprintf(stderr, "!\n");
//	assert(ch[v][0] == u);
//	assert(v == fa[u]);
//	assert(sz_all[u] - sz_sub[u] == 1);

	int sz1 = sz_all[u];
	int sz0 = sz_all[v] - sz1;
//	fprintf(stderr, "%d %d\n", u, v);

	tot -= sz_all[v] >= K;
	tot += sz1 >= K;
	tot += sz0 >= K;

	ch[v][0] = 0, fa[u] = 0;
	push_up(v);
}

void link(int u, int v)
{
//	assert(find(u) != find(v));
	make_root(u);
	make_root(v); 
	tot -= sz_all[u] >= K;
	tot -= sz_all[v] >= K;

	fa[v] = u;
	sz_sub[u] += sz_all[v];
	push_up(u);
	tot += sz_all[u] >= K;
}

}lct;

std::set<PII> S;

bool link(int i)
{
	int u = edge[i].u, v = edge[i].v;
	int w = edge[i].wb;
	if (lct.find(u) == lct.find(v)) {
		PII o = lct.query(u, v);
		if (o.first <= w) return false;
		S.erase(o);
//		fprintf(stderr, "%d\n", o.second);
		lct.cut(edge[o.second].u, o.second + N);
		lct.cut(edge[o.second].v, o.second + N);
	}
//	fprintf(stderr, "%d %d edge_id = %d\n", u, v, cur);
//	assert(lct.find(u) != lct.find(v));
	lct.link(u, i + N), lct.link(v, i + N);
	return true;
}

bool cut(int i)
{
	int a = edge[i].u, b = i + N;
	lct.make_root(a);
	lct.access(b);
	lct.splay(b);

	int sz1 = lct.sz_all[a];
	int sz0 = lct.sz_all[b] - sz1;

	int tot = ::tot;
	tot -= lct.sz_all[b] >= K;
	tot += sz1 >= K;
	tot += sz0 >= K;

	if (tot) {
		lct.cut(edge[i].u, i + N);
		lct.cut(edge[i].v, i + N);
		return true;
	}

	return false;
}


int main()
{
	freopen("mincost.in", "r", stdin);
	freopen("mincost.out", "w", stdout);

	N = read(); M = read(), K = read();
	for (int i = 1; i <= N; ++i) {
		a[i] = read(), b[i] = read();
	}

	if (K == 1) {
		int ans = inf;
		for (int i = 1; i <= N; ++i) 
			chkmin(ans, a[i] + b[i]);
		printf("%d\n", ans);
		return 0;
	}

	for (int i = 1; i <= M; ++i) {
		int u = read(), v = read();
		int wa = std::max(a[u], a[v]);
		int wb = std::max(b[u], b[v]);
		edge[i] = (Edge) {u, v, wa, wb};
	}

	std::sort(edge + 1, edge + M + 1);

	int ans = inf;
	for (int i = 1; i <= M; ++i) {
//		cur = i;
		if (link(i)) {
			S.insert(PII(edge[i].wb, i));
		}
//		fprintf(stderr, "%d %d %d\n", i, edge[i].u, edge[i].v);
		while (true) {
			std::set<PII>::iterator it = --S.end();
			if (cut(it->second)) {
				S.erase(it);
			}
			else break;
		}

		if (tot) {
			chkmin(ans, (--S.end())->first + edge[i].wa);
		}
	}

	if (ans >= inf) 
		printf("no solution\n");
	else
		printf("%d\n", ans);
//	fprintf(stderr, "%lf\n", 1.0 * clock()/CLOCKS_PER_SEC);

	return 0;
}

posted @ 2018-04-09 21:42  pbvrvnq  阅读(87)  评论(0编辑  收藏  举报