• POJ 3237 Tree 树链剖分


    题意:

    给出一棵树,每条边有一个权值。下面有3种操作:

    • 改变某条边的权值
    • 将一条路径上的所有边的权值取反
    • 查询一条路径上的最大权值

    分析:

    因为是线段树成段取反操作,可以先打个neg标记,表示这段区间的数是否取反。
    再维护区间最大值和最小值,取反之后,新区间的最大值是原来最小值的相反数,新区间最小值是原来最大值的相反数。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int maxn = 10000 + 10;
    const int maxnode = maxn * 4;
    
    struct Edge
    {
    	int v, nxt;
    	Edge() {}
    	Edge(int v, int nxt): v(v), nxt(nxt) {}
    };
    
    int n, u[maxn], v[maxn], w[maxn];
    int ecnt, head[maxn];
    Edge edges[maxn * 2];
    
    void AddEdge(int u, int v) {
    	edges[++ecnt] = Edge(v, head[u]);
    	head[u] = ecnt;
    	edges[++ecnt] = Edge(u, head[v]);
    	head[v] = ecnt;
    }
    
    int tot;
    int sz[maxn], fa[maxn], dep[maxn], son[maxn], up[maxn];
    int id[maxn], pos[maxn], top[maxn];
    
    void dfs(int u) {
    	sz[u] = 1; son[u] = 0;
    	for(int i = head[u]; i; i = edges[i].nxt) {
    		int v = edges[i].v;
    		if(v == fa[u]) continue;
    		fa[v] = u;
    		dep[v] = dep[u] + 1;
    		up[v] = (i + 1) / 2;
    		dfs(v);
    		sz[u] += sz[v];
    		if(sz[v] > sz[son[u]]) son[u] = v;
    	}
    }
    
    void dfs2(int u, int tp) {
    	top[u] = tp;
    	id[u] = tot;
    	pos[tot++] = up[u];
    	if(son[u]) dfs2(son[u], tp);
    	for(int i = head[u]; i; i = edges[i].nxt) {
    		int v = edges[i].v;
    		if(v == fa[u] || v == son[u]) continue;
    		dfs2(v, v);
    	}
    }
    
    int maxv[maxnode], minv[maxnode], neg[maxnode];
    
    void pushup(int o) {
    	maxv[o] = max(maxv[o<<1], maxv[o<<1|1]);
    	minv[o] = min(minv[o<<1], minv[o<<1|1]);
    }
    
    void build(int o, int L, int R) {
    	if(L == R) {
    		maxv[o] = minv[o] = w[pos[L]];
    		neg[o] = 0;
    		return;
    	}
    	int M = (L + R) / 2;
    	build(o<<1, L, M);
    	build(o<<1|1, M+1, R);
    	pushup(o);
    }
    
    void Inverse(int& a, int &b) {
    	swap(a, b); a = -a; b = -b;
    }
    
    void pushdown(int o) {
    	if(neg[o]) {
    		neg[o<<1] ^= 1;
    		neg[o<<1|1] ^= 1;
    		Inverse(maxv[o<<1], minv[o<<1]);
    		Inverse(maxv[o<<1|1], minv[o<<1|1]);
    		neg[o] = 0;
    	}
    }
    
    void change(int o, int L, int R, int p, int v) {
    	if(L == R) {
    		maxv[o] = minv[o] = v;
    		neg[o] = 0;
    		return;
    	}
    	int M = (L + R) / 2;
    	pushdown(o);
    	if(p <= M) change(o<<1, L, M, p, v);
    	else change(o<<1|1, M+1, R, p, v);
    	pushup(o);
    }
    
    void update(int o, int L, int R, int qL, int qR) {
    	if(qL <= L && R <= qR) {
    		Inverse(minv[o], maxv[o]);
    		neg[o] ^= 1;
    		return;
    	}
    	int M = (L + R) / 2;
    	pushdown(o);
    	if(qL <= M) update(o<<1, L, M, qL, qR);
    	if(qR > M) update(o<<1|1, M+1, R, qL, qR);
    	pushup(o);
    }
    
    void UPDATE(int u, int v) {
    	int t1 = top[u], t2 = top[v];
    	while(t1 != t2) {
    		if(dep[t1] < dep[t2]) { swap(u, v); swap(t1, t2); }
    		update(1, 1, n, id[t1], id[u]);
    		u = fa[t1]; t1 = top[u];
    	}
    	if(u == v) return;
    	if(dep[u] > dep[v]) swap(u, v);
    	update(1, 1, n, id[son[u]], id[v]);
    }
    
    int qans;
    
    void query(int o, int L, int R, int qL, int qR) {
    	if(qL <= L && R <= qR) { qans = max(qans, maxv[o]); return; }
    	int M = (L + R) / 2;
    	pushdown(o);
    	if(qL <= M) query(o<<1, L, M, qL, qR);
    	if(qR > M) query(o<<1|1, M+1, R, qL, qR);
    }
    
    void QUERY(int u, int v) {
    	int t1 = top[u], t2 = top[v];
    	qans = -1000000000;
    	while(t1 != t2) {
    		if(dep[t1] < dep[t2]) { swap(u, v); swap(t1, t2); }
    		query(1, 1, n, id[t1], id[u]);
    		u = fa[t1]; t1 = top[u];
    	}
    	if(u == v) return;
    	if(dep[u] > dep[v]) swap(u, v);
    	query(1, 1, n, id[son[u]], id[v]);
    }
    
    int main()
    {
    	freopen("in.txt", "r", stdin);
    
    	int _; scanf("%d", &_);
    	while(_--) {
    		scanf("%d", &n);
    
    		ecnt = 0;
    		memset(head, 0, sizeof(head));
    		for(int i = 1; i < n; i++) {
    			scanf("%d%d%d", u + i, v + i, w + i);
    			AddEdge(u[i], v[i]);
    		}
    	
    		dfs(1);
    		tot = 0;
    		dfs2(1, 1);
    		n--;
    		memset(maxv, 0, sizeof(maxv));
    		memset(minv, 0, sizeof(minv));
    		memset(neg, 0, sizeof(neg));
    		for(int i = 1; i <= n; i++)
    			if(dep[u[i]] < dep[v[i]])
    				swap(u[i], v[i]);
    		build(1, 1, n);
    
    		char cmd[10];
    		int a, b;
    		while(scanf("%s", cmd) == 1) {
    			if(cmd[0] == 'D') break;
    			scanf("%d%d", &a, &b);
    			if(cmd[0] == 'C') change(1, 1, n, id[u[a]], b);
    			else if(cmd[0] == 'N') UPDATE(a, b);
    			else { QUERY(a, b); printf("%d
    ", qans); }
    		}
    	}
    
    	return 0;
    }
    
  • 相关阅读:
    在单向链表中删除指定的key
    双向链表反转
    单向链表反转
    认识异或运算
    二分查找
    插入排序
    冒泡排序
    选择排序
    go 语言环境安装
    欧几里得算法
  • 原文地址:https://www.cnblogs.com/AOQNRMGYXLMV/p/5186735.html
Copyright © 2020-2023  润新知