zoukankan      html  css  js  c++  java
  • B

    B - Housewife Wind

     POJ - 2763 

    因为树剖+线段树只能解决点权问题,所以这种题目给了边权的一般要转化成点权。

    知道这个以后这个题目就很简单了。

    怎么转化呢,就把这个边权转化为两点之间深度更大的那个就可以了。

    还要注意的是,这个公共祖先的点权要被减去。

    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <iostream>
    #include <algorithm>
    #include <cstdlib>
    #include <vector>
    #include <stack>
    #include <map>
    #include <string>
    #define inf 0x3f3f3f3f
    #define inf64 0x3f3f3f3f3f3f3f3f
    using namespace std;
    typedef long long ll;
    const int maxn = 4e5 + 10;
    
    int f[maxn];//f 保存u的父亲节点
    int dep[maxn];//dep保存节点u 的深度
    int siz[maxn];//siz保存以u为根的子节点的个数
    int son[maxn];//son 保存u的重儿子
    int rk[maxn];//rk当前dfs序在树中所对应的节点
    int top[maxn];// top保存当前结点所在链的顶端结点
    int id[maxn];//dfs的执行顺序
    
    int a[maxn], n;
    ll sum[maxn * 4];
    //------------------线段树部分---------------//
    void push_up(int id) {
    	sum[id] = sum[id << 1] + sum[id << 1 | 1];
    }
    
    void build(int id, int l, int r) {
    	if (l == r) {
    		sum[id] = a[rk[l]];
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(id << 1, l, mid);
    	build(id << 1 | 1, mid + 1, r);
    	push_up(id);
    }
    
    void update(int id, int l, int r, int pos, int val) {
    	if (l == r) {
    		sum[id] = val;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	if (pos <= mid) update(id << 1, l, mid, pos, val);
    	else  update(id << 1 | 1, mid + 1, r, pos, val);
    	push_up(id);
    }
    
    ll query(int id, int l, int r, int x, int y) {
    	// printf("id=%d l=%d r=%d x=%d y=%d
    ", id, l, r, x, y);
    	if (x <= l && y >= r) return sum[id];
    	int mid = (l + r) >> 1;
    	ll ans = 0;
    	if (x <= mid) ans = (ans + query(id << 1, l, mid, x, y));
    	if (y > mid) ans = (ans + query(id << 1 | 1, mid + 1, r, x, y));
    	return ans;
    }
    
    
    
    //------------------------树链剖分-------------------//
    // int f[maxn];//f 保存u的父亲节点
    // int dep[maxn];//dep保存节点u 的深度
    // int siz[maxn];//siz保存以u为根的子节点的个数
    // int son[maxn];//son 保存u的重儿子
    // int rk[maxn];//rk当前dfs序在树中所对应的节点
    // int top[maxn];// top保存当前结点所在链的顶端结点
    // int id[maxn];//dfs的执行顺序
    struct node {
    	int v, nxt;
    	node(int v = 0, int nxt = 0) : v(v), nxt(nxt) {}
    }ex[maxn];
    int head[maxn], cnt = 0, tot;
    void init() {
    	cnt = 0, tot = 0;
    	memset(son, 0, sizeof(son));
    	memset(head, -1, sizeof(head));
    }
    void add(int u, int v, int w) {
    	ex[cnt] = node(v, head[u]);;
    	head[u] = cnt++;
    	ex[cnt] = node(u, head[v]);
    	head[v] = cnt++;
    }
    
    
    void dfs1(int u, int fa, int depth) {
    	f[u] = fa; dep[u] = depth; siz[u] = 1;
    	for (int i = head[u]; i != -1; i = ex[i].nxt) {
    		int v = ex[i].v;
    		if (v == fa) continue;
    		dfs1(v, u, depth + 1);
    		siz[u] += siz[v];
    		if (siz[v] > siz[son[u]]) son[u] = v;
    	}
    }
    
    void dfs2(int u, int t) {
    	top[u] = t;
    	id[u] = ++tot;//标记dfs序
    	rk[tot] = u;//序号tot对应的结点u
    	if (!son[u]) return;
    	dfs2(son[u], t);
    	/*我们选择优先进入重儿子来保证一条重链上各个节点dfs序连续,
    	一个点和它的重儿子处于同一条重链,所以重儿子所在重链的顶端还是t*/
    	for (int i = head[u]; i != -1; i = ex[i].nxt) {
    		int v = ex[i].v;
    		if (v != son[u] && v != f[u]) dfs2(v, v);//一个点位于轻链底端,那么它的top必然是它本身
    	}
    }
    
    ll query2(int x, int y) {
    	ll ret = 0;
    	while (top[x] != top[y]) {
    		if (dep[top[x]] < dep[top[y]]) swap(x, y);
    		ret = (ret + query(1, 1, n, id[top[x]], id[x]));
    		x = f[top[x]];
    	}
    	if (dep[x] > dep[y]) swap(x, y);
    	ret = ret + query(1, 1, n, id[x], id[y]) - query(1, 1, n, id[x], id[x]);
    	return ret;
    }
    
    //------------------树链剖分结束-------------------//
    
    struct heapnode {
    	int u, v, w;
    	heapnode(int u = 0, int v = 0, int w = 0) :u(u), v(v), w(w) {}
    }exa[maxn];
    
    int main() {
    	
    	int m, s;
    	while(scanf("%d%d%d", &n, &m, &s)!=EOF)
    	{
    		init();
    		for (int i = 1; i < n; i++) {
    			int u, v, w;
    			scanf("%d%d%d", &u, &v, &w);
    			add(u, v, w);
    			exa[i] = heapnode(u, v, w);
    		}
    		dfs1(1, -1, 1), dfs2(1, 1);
    		for (int i = 1; i < n; i++) {
    			heapnode now = exa[i];
    			if (dep[now.u] > dep[now.v]) swap(now.u, now.v);
    			a[now.v] = now.w;
    		}
    		build(1, 1, n);
    		while (m--) {
    			int opt, i, w, u;
    			scanf("%d", &opt);
    			if (opt == 0) {
    				scanf("%d", &u);
    				int ans = query2(s, u), x;
    				printf("%d
    ", ans);
    				s = u;
    			}
    			else {
    				scanf("%d%d", &i, &w);
    				heapnode now = exa[i];
    				if (dep[now.u] > dep[now.v]) swap(now.u, now.v);
    				int num = now.v;
    				update(1, 1, n, id[num], w);
    			}
    		}
    	}
    	return 0;
    }
    

      

  • 相关阅读:
    hdu6229 Wandering Robots 2017沈阳区域赛M题 思维加map
    hdu6223 Infinite Fraction Path 2017沈阳区域赛G题 bfs加剪枝(好题)
    hdu6438 Buy and Resell 买卖物品 ccpc网络赛 贪心
    hdu6441 Find Integer 求勾股数 费马大定理
    bzoj 1176 Mokia
    luogu 3415 祭坛
    bzoj 1010 玩具装箱
    bzoj 3312 No Change
    luogu 3383【模板】线性筛素数
    bzoj 1067 降雨量
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/11346398.html
Copyright © 2011-2022 走看看