bzoj4538: [Hnoi2016]网络

4538: [Hnoi2016]网络

Time Limit: 20 Sec Memory Limit: 128 MB

Description

一个简单的网络系统可以被描述成一棵无根树。每个节点为一个服务器。连接服务器与服务器的数据线则看做一条树边。两个服务器进行数据的交互时,数据会经过连接这两个服务器的路径上的所有服务器(包括这两个服务器自身)。由于这条路径是唯一的,当路径上的某个服务器出现故障,无法正常运行时,数据便无法交互。此外,每个数据交互请求都有一个重要度,越重要的请求显然需要得到越高的优先处理权。现在,你作为一个网络系统的管理员,要监控整个系统的运行状态。系统的运行也是很简单的,在每一个时刻,只有可能出现下列三种事件中的一种:1. 在某两个服务器之间出现一条新的数据交互请求;2. 某个数据交互结束请求;3. 某个服务器出现故障。系统会在任何故障发生后立即修复。也就是在出现故障的时刻之后,这个服务器依然是正常的。但在服务器产生故障时依然会对需要经过该服务器的数据交互请求造成影响。你的任务是在每次出现故障时,维护未被影响的请求中重要度的最大值。注意,如果一个数据交互请求已经结束,则不将其纳入未被影响的请求范围。

Input

第一行两个正整数n,m,分别描述服务器和事件个数。服务器编号是从1开始的,因此n个服务器的编号依次是1,2,3,…,n。接下来n-1行,每行两个正整数u,v,描述一条树边。u和v是服务器的编号。接下来m行,按发生时刻依次描述每一个事件;即第i行(i=1,2,3,…,m)描述时刻i发生的事件。每行的第一个数type描述事件类型,共3种类型:(1)若type=0,之后有三个正整数a,b,v,表示服务器a,b之间出现一条重要度为v的数据交互请求;(2)若type=1,之后有一个正整数t,表示时刻t(也就是第t个发生的事件)出现的数据交互请求结束;(3)若type=2,之后有一个正整数x,表示服务器x在这一时刻出现了故障。对于每个type为2的事件,就是一次询问,即询问“当服务器x发生故障时,未被影响的请求中重要度的最大值是多少?”注意可能有某个服务器自身与自身进行数据交互的情况。2 ≤ n ≤ 10^5, 1 ≤ m ≤ 2×10^5,其他的所有输入值不超过 10^9。

Output

对于每个type=2的事件,即服务器出现故障的事件,输出一行一个整数,描述未被影响的请求中重要度的最大
值。如果此时没有任何请求,或者所有请求均被影响,则输出-1。

Sample Input

13 23

1 2

1 3

2 4

2 5

3 6

3 7

4 8

4 9

6 10

6 11

7 12

7 13

2 1

0 8 13 3

0 9 12 5

2 9

2 8

2 2

0 10 12 1

2 2

1 3

2 7

2 1

0 9 5 6

2 4

2 5

1 7

0 9 12 4

0 10 5 7

2 1

2 4

2 12

1 2

2 5

2 3

Sample Output

-1

3

5

-1

1

-1

1

1

3

6

7

7

4

6

解法

此题的解法其实比较明显,可以直接树剖,亦可以二分。

bzoj新加数据一组,不过通过discuss我们发现了通过此题的方法。

immortalCO @ 2016-06-04 16:14:37 [ Quote ] [ Edit ] [ Delete ] 4#
这个数据卡的是“以1为根、邻接表的顺序和输入相反”的树链剖分
一个同学把找重儿子的大小关系由>改成>=就AC了…………

树剖

#include <bits/stdc++.h>
using namespace std;
#define N 100003
#define wlp while
#define rep(i, l, r) for (register int i = l; i <= r; ++i)

template<class integer>
inline void gi(integer &a) {
	static char c;
	wlp (c = getchar(), c < '0'); a = c - '0';
	wlp (c = getchar(), '-' < c) a = (a << 3) + (a << 1) + c - '0';
}

struct heap {
	priority_queue<int> a, b;
	void erase(const int &x) {
		b.push(x);
	}
	int top() {
		wlp (!b.empty() && a.top() == b.top()) {
			a.pop();
			b.pop();
		}
		return a.top();
	}
	void push(const int &x) {
		a.push(x);
	}
	heap() {
		a.push(-1);
	}
}hp[N<<2|1];

struct event {
	int a, b, v;
}a[N];

struct edge {
	int t;
	edge *n;
}me[N<<1|1], *ce = me, *g[N];
#define adde(a, b) (*ce = (edge){b, g[a]}, g[a] = ce++)
#define FOR(a, b) for (edge *a = g[b]; a; a = a->n)
int fa[N], son[N], tp[N], dep[N], dfn[N], _dfn;
void d1(int u) {
	static int sz[N];
	sz[u] = 1;
	FOR(it, u) if (it->t ^ fa[u]) {
		fa[it->t] = u;
		dep[it->t] = dep[u] + 1;
		d1(it->t);
		if (sz[it->t] >= sz[son[u]]) son[u] = it->t;
		sz[u] += sz[it->t];
	}
}
void d2(int u, int anc) {
	dfn[u] = ++_dfn;
	tp[u] = anc;
	if (son[u]) d2(son[u], anc);
	FOR(it, u) if (!tp[it->t]) d2(it->t, it->t);
}

#define ls u<<1
#define rs u<<1|1
void upd(int u, int l, int r, const int &x, const int &y, const int &v, const bool &flag) {
	if (x <= l && r <= y) 
		return flag ? hp[u].push(v) : hp[u].erase(v);
	int m = l + r >> 1;
	if (x <= m) upd(ls, l, m, x, y, v, flag);
	if (y >  m) upd(rs, m + 1, r, x, y, v, flag);
}

int quy(const int &p) {
	static int u, l, r, v, t, m;
	for (u = 1, l = 1, r = _dfn, v = -1; l ^ r; ) {
		if (v < (t = hp[u].top())) v = t;
		m = l + r >> 1;
		if (p <= m) u = ls, r = m;
		else u = rs, l = m + 1;
	}
	if (v < (t = hp[u].top())) v = t;
	return v;
}

pair<int, int>sg[N];
inline void modify(int u, int v, const int &val, const bool &flag) {
	static int cnt, i, l, r, pre;
	for (cnt = 0; tp[u] ^ tp[v];)
		if (dep[tp[u]] < dep[tp[v]]) {
			sg[cnt++] = pair<int, int>(dfn[tp[v]], dfn[v]);
			v = fa[tp[v]];
		} else {
			sg[cnt++] = pair<int, int>(dfn[tp[u]], dfn[u]);
			u = fa[tp[u]];
		}
	if (dep[u] < dep[v]) u ^= v ^= u ^= v;
	sg[cnt++] = pair<int, int>(dfn[v], dfn[u]);
	sort(sg, sg + cnt);
	pre = 0;
	for (i = 0; i < cnt; ++i) {
		l = pre + 1;
		r = sg[i].first - 1;
		pre = sg[i].second;
		if (l <= r) upd(1, 1, _dfn, l, r, val, flag);
	}
	if (pre ^ _dfn) upd(1, 1, _dfn, pre + 1, _dfn, val, flag);
}

int main() {
	int n, m, u, v, type, x;
	gi(n), gi(m);
	rep(i, 2, n) {
		gi(u), gi(v);
		adde(u, v);
		adde(v, u);
	}
	d1(1); d2(1, 1);
	rep(i, 1, m) {
		gi(type);
		if (!type) {
			gi(u), gi(v), gi(x);
			a[i] = (event) {u, v, x};
			modify(u, v, x, true);
		} else if (type & 1) {
			gi(x);
			modify(a[x].a, a[x].b, a[x].v, false);
		} else gi(x), printf("%d\n", quy(dfn[x]));
	}
	return 0;
}

二分答案+线段树(整体二分)

相当于是求不包含一个点的所有链中的最大权值。

二分一个权值,询问权值大于它的链的交集是否包含这个点。

于是问题就转化为如何求链的交集。

用线段树维护链的交集,每个点表示权值在这个区间内的链的交集,在线段树上二分答案即可。预处理ST表,每次O(1)求LCA、O(1)求链的交集。

代码:http://www.cnblogs.com/Ngshily/p/5413933.html

不过蒟蒻更喜欢用树剖啊

#include <bits/stdc++.h>
using namespace std;
#define N 200003
#define wlp while
#define rep(i, l, r) for (register int i = l; i <= r; ++i)

template<class integer>
inline void gi(integer &a) {
	static char c;
	wlp (c = getchar(), c < '0'); a = c - '0';
	wlp (c = getchar(), '-' < c) a = (a << 3) + (a << 1) + c - '0';
}

typedef int arr[N];
arr tp, fa, son, dep, in, ou, tr, ans;
int dfn;

struct node {
	int a, b, v, lca;
}a[N];

struct opt {
	int type, x, id;
}q[N], tq[N];

struct edge {
	int t;
	edge *n;
}me[N<<1|1], *ce = me, *g[N];
#define adde(a, b) (*ce = (edge){b, g[a]}, g[a] = ce++)
#define FOR(a, b) for (edge *a = g[b]; a; a = a->n)
void d1(int u) {
	static int sz[N];
	sz[u] = 1;
	FOR(it, u) if (it->t ^ fa[u]) {
		fa[it->t] = u;
		dep[it->t] = dep[u] + 1;
		d1(it->t);
		if (sz[it->t] > sz[son[u]]) son[u] = it->t;
		sz[u] += sz[it->t];
	}
}
void d2(int u, int anc) {
	in[u] = ++dfn;
	tp[u] = anc;
	if (son[u]) d2(son[u], anc);
	FOR(it, u) if (!tp[it->t]) d2(it->t, it->t);
	ou[u] = dfn;
}

inline int Lca(int u, int v) {
	wlp (tp[u] ^ tp[v]) dep[tp[u]] < dep[tp[v]] ? v = fa[tp[v]] : u = fa[tp[u]];
	return dep[u] < dep[v] ? u : v;
}

inline void add(int x, const int &delta) {
	for (; x <= dfn; x += x & -x)
		tr[x] += delta;
}

inline int sum(int x) {
	static int r;
	for (r = 0; 0 < x; x ^= x & -x)
		r += tr[x];
	return r;
}

inline int quy(const int &u) {
	return sum(ou[u]) - sum(in[u] - 1);
}

inline void modify(const int &id, const int &delta) {
	add(in[a[id].a], delta);
	add(in[a[id].b], delta);
	add(in[a[id].lca], -delta);
	if (fa[a[id].lca]) add(in[fa[a[id].lca]], -delta);
}

void divide(int l, int r, int L, int R) {
	if (L >= R || l > r) {
		rep(i, l, r) 
			if (q[i].type == 2) ans[q[i].id] = L;
		return;
	}
	int mid = L + R >> 1, it = l - 1, cnt = 0, _t = 0, t;
	rep(i, l, r) 
		if (q[i].type == 2) (quy(q[i].x) ^ _t) ? tq[++cnt] = q[i] : q[++it] = q[i];
		else {
			t = q[i].type ? -1 : 1;
			if (a[q[i].x].v <= mid) q[++it] = q[i];
			else {
				tq[++cnt] = q[i];
				_t += t;
				modify(q[i].x, t);
			}
		}
	rep(i, 1, cnt) {
		if (tq[i].type ^ 2) {
			t = tq[i].type ? 1 : -1;
			modify(tq[i].x, t);
		}
		q[i + it] = tq[i];
	}
	divide(l, it, L, mid);
	divide(it + 1, r, mid + 1, R);
}

int main() {
	int n, m, u, v, mx = -1;
	gi(n), gi(m);
	rep(i, 2, n) {
		gi(u), gi(v);
		adde(u, v);
		adde(v, u);
	}
	d1(1);
	d2(1, 1);
	rep(i, 1, m) {
		gi(q[i].type);
		q[i].id = i;
		if (q[i].type) gi(q[i].x);
		else {
			gi(a[i].a), gi(a[i].b), gi(a[i].v);
			a[i].lca = Lca(a[i].a, a[i].b);
			q[i].x = i;
			if (mx < a[i].v) mx = a[i].v;
		}
		ans[i] = -2;
	}
	divide(1, m, -1, mx);
	rep(i, 1, m) 
		if (ans[i] ^ -2) printf("%d\n", ans[i]);
	return 0;
}
posted @ 2017-02-13 18:47  cycleke  阅读(204)  评论(0编辑  收藏  举报