[CTSC2008]网络管理

题面

题解

带修改的主席树???我可没有那么勤快去写个树套树

只要它不强制在线,我就可以用整体二分做

思路大致与【ZJOI2013】K大数查询相似

只不过放在树上做,还带修改

同样处理出询问,并且一个修改操作要拆分成两个

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
#define RG register
#define file(x) freopen(#x".in", "r", stdin);freopen(#x".out", "w", stdout);
#define clear(x, y) memset(x, y, sizeof(x));

inline int read()
{
	int data = 0, w = 1;
	char ch = getchar();
	while(ch != '-' && (ch < '0' || ch > '9')) ch = getchar();
	if(ch == '-') w = -1, ch = getchar();
	while(ch >= '0' && ch <= '9') data = data * 10 + (ch ^ 48), ch = getchar();
	return data*w;
}

const int maxn(80010);
struct edge { int next, to; } e[maxn << 1];
int head[maxn], e_num, n, q;
inline void add_edge(int from, int to) { e[++e_num] = (edge) {head[from], to}; head[from] = e_num; }
int pos[maxn], fa[maxn], size[maxn], heavy[maxn], belong[maxn], dep[maxn], cnt;

void dfs(int x)
{
	size[x] = 1;
	for(RG int i = head[x]; i; i = e[i].next)
	{
		int to = e[i].to; if(to == fa[x]) continue;
		fa[to] = x; dep[to] = dep[x] + 1; dfs(to);
		size[x] += size[to];
		if(size[heavy[x]] < size[to]) heavy[x] = to;
	}
}

void dfs(int x, int chain)
{
	pos[x] = ++cnt; belong[x] = chain;
	if(!heavy[x]) return;
	dfs(heavy[x], chain);
	for(RG int i = head[x]; i; i = e[i].next)
	{
		int to = e[i].to; if(to == fa[x] || to == heavy[x]) continue;
		dfs(to, to);
	}
}

int sum, ans[maxn], c[maxn], T[maxn];
struct qry { int k, a, b, id, opt; } p[maxn << 1], pl[maxn << 1], pr[maxn << 1];
inline void add(int x, int v) { while(x <= n) c[x] += v, x += x & -x; }
inline int query(int x) { int ans = 0; while(x) ans += c[x], x -= x & -x; return ans; }
inline int LCA(int a, int b)
{
	while(belong[a] ^ belong[b])
	{
		if(pos[belong[a]] < pos[belong[b]]) std::swap(a, b);
		a = fa[belong[a]];
	}
	return pos[a] < pos[b] ? a : b;
}

inline int Query(int a, int b)
{
	int ans = 0;
	while(belong[a] ^ belong[b])
	{
		if(pos[belong[a]] < pos[belong[b]]) std::swap(a, b);
		ans += query(pos[a]) - query(pos[belong[a]] - 1);
		a = fa[belong[a]];
	}
	if(pos[a] < pos[b]) std::swap(a, b);
	return ans + query(pos[a]) - query(pos[b] - 1);
}

void Div(int l, int r, int ql, int qr)
{
	if(ql > qr) return;
	if(l == r) { for(RG int i = ql; i <= qr; i++) if((!p[i].opt) && (~ans[p[i].id])) ans[p[i].id] = l; return; }

	int mid = (l + r) >> 1, tl = 0, tr = 0;
	for(RG int i = ql; i <= qr; i++)
	{
		if(p[i].k == 0)
			if(p[i].b <= mid) pl[++tl] = p[i];
			else pr[++tr] = p[i], add(pos[p[i].a], p[i].id);
		else
		{
			int sum = Query(p[i].a, p[i].b);
			if(sum >= p[i].k) pr[++tr] = p[i];
			else p[i].k -= sum, pl[++tl] = p[i];
		}
	}

	for(RG int i = ql; i <= qr; i++) if(p[i].opt && p[i].b > mid) add(pos[p[i].a], -p[i].id);
	for(RG int i = 1; i <= tl; i++) p[ql + i - 1] = pl[i];
	for(RG int i = 1; i <= tr; i++) p[ql + tl + i - 1] = pr[i];
	Div(l, mid, ql, ql + tl - 1); Div(mid + 1, r, ql + tl, qr);
}

int main()
{
#ifndef ONLINE_JUDGE
	file(cpp);
#endif

	n = read(); q = read(); int tot = 0;
	for(RG int i = 1; i <= n; i++) p[++tot] = (qry) {0, i, T[i] = read(), 1, 1};
	for(RG int i = 1, a, b; i < n; i++)
		a = read(), b = read(), add_edge(a, b), add_edge(b, a);
	dfs(1); dfs(1, 1);

	for(RG int i = 1, k, a, b; i <= q; i++)
	{
		k = read(); a = read(); b = read();
		if(k)
		{
			p[++tot] = (qry) {k, a, b, ++sum, 0};
			int dis = dep[a] + dep[b] - (dep[LCA(a, b)] << 1) + 1;
			if(p[tot].k > dis) ans[p[tot].id] = -1;
		}
		else p[++tot] = (qry) {0, a, T[a], -1, 1}, p[++tot] = (qry) {0, a, T[a] = b, 1, 1};
	}

	Div(1, 100000000, 1, tot);
	for(RG int i = 1; i <= sum; i++)
		(~ans[i]) ? printf("%d\n", ans[i]) : puts("invalid request!");
	return 0;
}
posted @ 2018-10-16 21:57  xgzc  阅读(207)  评论(0编辑  收藏  举报