zoukankan      html  css  js  c++  java
  • P3258 [JLOI2014]松鼠的新家题解

    题目描述

    松鼠的新家是一棵树,前几天刚刚装修了新家,新家有(n)个房间,并且有(n-1)根树枝连接,每个房间都可以相互到达,且俩个房间之间的路线都是唯一的。天哪,他居然真的住在”树“上。

    松鼠想邀请小熊维尼前来参观,并且还指定一份参观指南,他希望维尼能够按照他的指南顺序,先去(a_1),再去(a_2),......,最后到(a_n),去参观新家。可是这样会导致维尼重复走很多房间,懒惰的维尼不停地推辞。可是松鼠告诉他,每走到一个房间,他就可以从房间拿一块糖果吃。

    维尼是个馋家伙,立马就答应了。现在松鼠希望知道为了保证维尼有糖果吃,他需要在每一个房间各放至少多少个糖果。

    因为松鼠参观指南上的最后一个房间(a_n)是餐厅,餐厅里他准备了丰盛的大餐,所以当维尼在参观的最后到达餐厅时就不需要再拿糖果吃了。

    输入格式

    第一行一个整数(n),表示房间个数第二行(n)个整数,依次描述(a_1-a_n)

    接下来(n-1)行,每行两个整数(x)(y),表示标号(x)(y)的两个房间之间有树枝相连。

    输出格式

    一共(n)行,第(i)行输出标号为i的房间至少需要放多少个糖果,才能让维尼有糖果吃。

    输入输出样例

    输入 #1

    5
    1 4 5 3 2
    1 2
    2 4
    2 3
    4 5

    输出 #1

    1
    2
    1
    2
    1

    说明/提示

    (2<= n <=300000)

    解析:

    LCA + 树上差分

    对于访问序号我们将其变成边的形式。

    对于所有的的边,

    我们会发现第一条和最后一条是特殊的。

    1. 第一条是两个端点都是包含的, 即在两个端点上都放糖果:[u,v]

    2. 最后一条是两个端点都不包含, 即在两个端点上不放糖果:(u,v)

    3. 其余的路径都是一样的,前一个包含,后一个不包含:[u,v)

    f数组是倍增lca数组,u和v分别是一边的端点。

    1. 先看第一条边,直接进行树上差分,无特殊处理。

    2. 最后一条边,我们要进行讨论,一共有3种情况:

      1. u != LCA && v != LCA,那么我们要差分的边就是f[u][0]-f[v][0].
      2. u == LCA && v != LCA,那么我们要差分的边就是son[u]-f[v][0].
      3. u != LCA && v == LCA,那么我们要差分的边就是f[u][0]-son[v].
    3. 其余的边,也是讨论3种情况:

      1. u != LCA && v != LCA,那么我们要差分的边就是f[u][0]-v.
      2. u == LCA && v != LCA,那么我们要差分的边就是son[u]-v.
      3. u != LCA && v == LCA,那么我们要差分的边就是f[u][0]-v

    做完这些,就是树上差分的板子了,这里就不赘述了。

    #include <cstdio>
    #include <cmath>
    #include <iostream>
    #include <cstdlib>
    #include <vector>
    #include <map>
    #include <cstring>
    #include <queue>
    #include <stack>
    #include <algorithm>
    #define re register
    #define gc getchar
    inline int read() {
    	int s = 0, f = 1; char ch = gc();
    	while(ch < '0' || ch > '9') {if(ch == '-') f = -1; ch = gc();}
    	while(ch >= '0' && ch <= '9') s = s * 10 + ch - '0', ch = gc();
    	return s * f;
    }
    inline int min(int a, int b) {return a < b ? a : b;}
    inline int max(int a, int b) {return a > b ? a : b;}
    const int INF = 0x7fffffff;
    const int Max = 600012;
    const int mod = 19260817;
    const int N = 1000007;
    struct Candy {
    	int net, to;
    }t[Max];
    int n, head[Max], cnt, f[Max][21];
    int x[Max], y[Max], k[Max], deep[Max];
    inline void insert(int u, int v) {
    	t[++cnt].to = v;
    	t[cnt].net = head[u];
    	head[u] = cnt;
    }
    void dfs(int x, int Fa) {
    	f[x][0] = Fa; deep[x] = deep[Fa] + 1;
    	for(int i = 1; (1 << i) <= deep[x]; i++)
    		f[x][i] = f[f[x][i-1]][i-1];
    	int v;
    	for(re int i = head[x]; i; i = t[i].net) {
    		v = t[i].to;
    		if(v == Fa) continue;
    		dfs(v,x);
    	}
    }
    int lca(int x, int y) {
    	if(deep[x] < deep[y]) std :: swap(x, y);
    	for(re int i = 21; i >= 0; -- i)
    		if(deep[x] - (1 << i) >= deep[y])
    			x = f[x][i];
    	if(x == y) return x;
    	for(re int i = 20; i >= 0; -- i)
    		if(f[x][i] == f[y][i]) continue;
    		else x = f[x][i], y = f[y][i];
    	return f[x][0];
    }
    void SUM(int x, int Fa) {
    	int v;
    	for(re int i = head[x]; i; i = t[i].net) {
    		v = t[i].to; if(v == Fa) continue;
    		SUM(v, x); k[x] += k[v];
    	}
    }
    int find_son(int x, int LCA) {
    	int depth = deep[LCA] + 1;
    	for(re int i = 21; i >= 0; -- i)
    		if(deep[x] - (1 << i) >= depth)
    			x = f[x][i];
    	return x;
    }
    int main() {
    	n = read(); int u, v; x[1] = read();
    	for(re int i = 1; i < n; ++ i) y[i] = read(), x[i+1] = y[i];
    	for(re int i = 1; i < n; ++ i)
    		u = read(), v = read(), insert(u,v), insert(v,u);
    	dfs(1,0);
    	int LCA = lca(x[n-1], y[n-1]); bool fg = 1;
    	if(x[n-1] != LCA && y[n-1] != LCA)
    		u = f[x[n-1]][0], v = f[y[n-1]][0];
    	else if(x[n-1] == LCA && y[n-1] != LCA) {
    		u = find_son(y[n-1], LCA), v = f[y[n-1]][0];
    		if(f[y[n-1]][0] == x[n-1]) fg = 0;
    	}
    	else if(x[n-1] != LCA && y[n-1] == LCA) {
    		u = f[x[n-1]][0], v = find_son(x[n-1], LCA);
    		if(f[x[n-1]][0] == y[n-1]) fg = 0;
    	}
    	LCA = lca(u, v);
    	if(fg) k[u] ++, k[v] ++, k[LCA] --, k[f[LCA][0]] --;
    	u = x[1]; v = y[1]; LCA = lca(u, v);
    	k[u] ++, k[v] ++, k[LCA] --, k[f[LCA][0]] --;
    	for(re int i = 2; i < n - 1; ++ i) {
    		LCA = lca(x[i], y[i]);
    		if(x[i] != LCA && y[i] != LCA)
    			u = f[x[i]][0], v = y[i];
    		else if(x[i] == LCA && y[i] != LCA)
    			u = find_son(y[i], LCA), v = y[i];
    		else if(x[i] != LCA && y[i] == LCA)
    			u = f[x[i]][0], v = y[i];
    		LCA = lca(u,v);
    		k[u] ++, k[v] ++, k[LCA] --, k[f[LCA][0]] --;
    	}
    	SUM(1,0);
    	for(re int i = 1; i <= n; ++ i) printf("%d
    ",k[i]);
    	return 0;
    }
    
  • 相关阅读:
    使用Connector/C++(VS2015)连接MySQL的完整例子
    一个表里有多个字段需要同时使用字典表进行关联显示,如何写sql查询语句
    Delphi连接MySql(待测试验证,使用mysql.pas未通过)
    MySQL5.5.51启用网络远程连接
    delphi做的程序如何连接SQL数据库
    定时删除所有文件夹下的_desktop.ini文件
    Delphi中打开网页连接的几种方法
    SQL增删改查
    ADOConnection断线重连
    TDBGridEh 标头排序
  • 原文地址:https://www.cnblogs.com/ypay/p/11635371.html
Copyright © 2011-2022 走看看