zoukankan      html  css  js  c++  java
  • 洛谷P3038 [USACO11DEC]牧草种植Grass Planting

    题目

    树链剖分或者树上差分

    树链剖分只能对点进行操作,所以把边权化为点权。树上化边权为点权的一般操作是把边权赋到深度较深的点里。

    然后用树链剖分+线段树更改权值路径和+单点查询即可解决该问题。

    #include <bits/stdc++.h>
    #define N 4001011
    #define ls l, mid, root << 1
    #define rs mid + 1, r, root << 1 | 1
    using namespace std;
    struct edg {
    	int to, nex;
    }e[N * 4];
    int lin[N], dep[N], fat[N], siz[N], son[N], data[N], dfn[N], top[N], temp[N], cnt, n, m, tot;//data[i]表示i的点权。 
    int tree[N << 2], lazy[N << 2];
    inline void add(int f, int t)//默认边权为0 
    {
    	e[++cnt].nex = lin[f];
    	e[cnt].to = t;
    	lin[f] = cnt;
    }
    void dfs1(int now, int fa)
    {
    	dep[now] = dep[fa] + 1;
    	fat[now] = fa;
    	siz[now] = 1;
    	for (int i = lin[now]; i; i = e[i].nex)
    	{
    		int to = e[i].to;
    		if (to == fa) continue;
    		dfs1(to, now);
    		siz[now] += siz[to];
    		if (siz[to] > siz[son[now]])
    			son[now] = to;
    	}
    }
    void dfs2(int now, int tes) //求出dfs序, 树链剖分求lca 
    {
    	dfn[now] = ++tot;//dfn是dfs序
    	top[now] = tes;
    	if (!son[now]) return;
    	dfs2(son[now], tes);
    	for (int i = lin[now]; i; i = e[i].nex)//找重链
    	{
    		int to = e[i].to;
    		if (to == fat[now] || to == son[now]) continue;
    		dfs2(to, to);
    	}
    }	
    inline void pushup(int root) {tree[root] = tree[root << 1] + tree[root << 1 | 1];}
    void build(int l, int r, int root)
    {	
    	if (l == r)
    	{
    		tree[root] = 0;
    		return;
    	}
    	int mid = (l + r) >> 1;
    	build(ls), build(rs);
    	pushup(root);
    }	
    void pushdown(int l, int r, int root)
    {
    	int mid = (l + r) >> 1;
     	if (lazy[root])
     	{
     		lazy[root << 1] += lazy[root];
     		lazy[root << 1 | 1] += lazy[root];
     		tree[root << 1] += lazy[root] * (mid - l + 1);
     		tree[root << 1 | 1] += lazy[root] * (r - mid);
     		lazy[root] = 0;
     	}
    }
    int query(int pos, int l, int r, int root)
    {
     	if (l == r)    
     		return tree[root];
     	int res = 0, mid = (l + r) >> 1;
     	pushdown(l, r, root);
     	if (pos <= mid)
     		res += query(pos, ls);
     	else  
     		res += query(pos, rs);
     	return res;
    }
    void update(int ql, int qr, int add, int l, int r, int root)
    {
    	if (ql <= l && r <= qr)
    	{
    		tree[root] += (r - l + 1) * add;
    		lazy[root] += add;
    		return;
    	}
    	pushdown(l, r, root);
    	int mid = (l + r) >> 1;
    	if (ql <= mid)
    		update(ql, qr, add, ls);
    	if (qr > mid)
    		update(ql, qr, add, rs);
    	pushup(root);
    }
    void U(int x, int y)
    {
    	while (top[x] != top[y])//找他们的lca
    	{
    		if (dep[top[x]] < dep[top[y]]) swap(x, y);
    		update(dfn[top[x]], dfn[x], 1, 1, n, 1);
    		x = fat[top[x]];
    	}
    	if (dep[x] > dep[y])
    		swap(x, y);
    	update(dfn[x] + 1, dfn[y], 1, 1, n, 1);
    }
    int main()
    {
    	scanf("%d%d", &n, &m);
    	for (int i = 1, a, b; i < n; i++) {scanf("%d%d", &a, &b), add(a, b), add(b, a);}
    	dfs1(1, 0);
    	dfs2(1, 1);
    	build(1, n, 1);
    	while (m--)
    	{
    		char flag; int a, b;
    		cin >> flag >> a >> b;
    		if (flag == 'P')
    			U(a, b);
    		else
    		{
    			if (dep[a] < dep[b]) swap(a, b);
    			printf("%d
    ", query(dfn[a], 1, n, 1));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    Android相关sdk使用
    Uniscribe文字自动换行
    Chrome RenderText分析(2)
    c++智能指针
    codepage IMLangCodePages
    GUI 快捷键的实现思路
    买车险
    九年---祝爱永存!
    算法
    Windows内核安全与驱动开发
  • 原文地址:https://www.cnblogs.com/liuwenyao/p/11804051.html
Copyright © 2011-2022 走看看