• HDU4916 Count on the path(树dp??)


    这道题的题意其实有点略晦涩,定义f(a,b)为 minimum of vertices not on the path between vertices a and b. 其实它加一个minimum index of vertices应该会好理解一点吧。看了一下题解,还有程序,才理清思路。

    首先比较直接的是如果两点的路径没有经过根节点1的话,那么答案就直接是1,否则的话就必然有从根节点出发的两条路径,题解里说的预处理出f[u]表示不在根节点到u的路径上的点的最小值,然后取f[u]和f[v]的最小值看了我半天。因为如果是这样的话,那么下面这个图不就可以轻易cha掉这种做法?

    1->2  1->3  2->4  4->6  4->7  3->5  5->8  5->9

    询问(6,8)的时候显然f(6)是3,f(8)是2,那么输出的答案就会是2,但实际上应该输出的是7。

    后来仔细探究了才发现,f[u]存的只是  从不在根节点到u的路径的最小值(其中不包括根节点到别的子节点的路径),换言之上面的f[6]里只存了7,f[8]里只存了9,所以min(7,9)=7。

    但是这个时候我们可能就会出错了,因为如果根节点如果连出去有第三条路径的话,那么这条路径的最小值我们是没有包含到的,所以对于根节点我们要存它最小值的子树,还有也要存对于每个节点它来自于哪个子树。

    剩下的就是一个类似树dp的过程了。

    然后题目还温馨提示了可能会超时,可能要写个输入挂什么的,所以写邻接表的可能都不能写vector的形式了吧。

    #pragma warning(disable:4996)
    #include <iostream>
    #include <cstring>
    #include <string>
    #include <vector>
    #include <cstdio>
    #include <cmath>
    #include <algorithm>
    using namespace std;
    
    #define maxn 1005000
    #define inf 0x3f3f3f3f
    
    int child[maxn][4];
    int subtree[maxn];
    int path[maxn];
    int fa[maxn];
    int bel[maxn];
    int que[maxn];
    int qh, qt;
    int n, nQ;
    
    int head[maxn];
    int nxt[maxn<<1];
    int vv[maxn<<1];
    int tot;
    
    void add_Edge(int u,int v)
    {
    	vv[tot] = v; nxt[tot] = head[u]; head[u] = tot++;
    }
    
    
    void bfs()
    {
    	qh = qt = 0;
    	que[qt++] = 1; fa[1] = -1;
    	while (qh < qt){
    		int u = que[qh++];
    		for (int i = head[u]; ~i; i=nxt[i]){
    			int v = vv[i];
    			if (v == fa[u]) continue;
    			fa[v] = u;
    			que[qt++] = v;
    		}
    	}
    	for (int i = 0; i <= n; ++i){
    		for (int j = 0; j < 4; ++j){
    			child[i][j] = inf;
    		}
    	}
    	for (int i = n - 1; i >= 0; --i){
    		int u = que[i]; subtree[u] = u;
    		for (int j = head[u]; ~j; j=nxt[j]){
    			int v = vv[j];
    			if (v == fa[u]) continue;
    			child[u][3] = subtree[v];
    			sort(child[u], child[u] + 4);
    		}
    		subtree[u] = min(subtree[u], child[u][0]);
    	}
    
    	qh = qt = 0;
    	for (int i = head[1]; ~i; i=nxt[i]){
    		int v = vv[i];
    		que[qt++] = v;
    		bel[v] = subtree[v];
    		path[v] = inf;
    	}
    	while (qh < qt){
    		int u = que[qh++];
    		for (int i = head[u]; ~i; i=nxt[i]){
    			int v = vv[i];
    			if (v == fa[u]) continue;
    			bel[v] = bel[u];
    			if (subtree[v] == child[u][0]){
    				path[v] = min(path[u], child[u][1]);
    			}
    			else{
    				path[v] = min(path[u], child[u][0]);
    			}
    			que[qt++] = v;
    		}
    		path[u] = min(path[u], child[u][0]);
    	}
    }
    
    
    int query(int qu, int qv){
    	if (qu > qv) swap(qu, qv);
    	if (qu != 1 && bel[qu] == bel[qv]) return 1;
    	int i = 0;
    	while (child[1][i] == bel[qu] || child[1][i] == bel[qv]){
    		i++;
    	}
    	int ret = qu == 1 ? path[qv] : min(path[qu], path[qv]);
    	ret = min(ret, child[1][i]);
    	return ret;
    }
    
    inline void scan(int &n)
    {
    	char cc;
    	for (; cc = getchar(), cc<'0' || cc>'9';);
    	n = cc - '0';
    	for (; cc = getchar(), cc >= '0'&&cc <= '9';)
    		n = n * 10 + cc - '0';
    }
    
    int main()
    {
    	while (cin >> n >> nQ){
    		tot = 0; memset(head, -1, sizeof(head));
    		int ui, vi;
    		for (int i = 0; i < n - 1; ++i){
    			//scan(ui); scan(vi);
    			scanf("%d%d", &ui, &vi);
    			add_Edge(ui, vi);
    			add_Edge(vi, ui);
    		}
    		bfs();
    		int last = 0;
    		for (int i = 0; i < nQ; ++i){
    			//scan(ui); scan(vi);
    			scanf("%d%d", &ui, &vi);
    			ui ^= last; vi ^= last;
    			printf("%d
    ", last=query(ui, vi));
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    vsphere中虚机的cpu热插拔和内存热添加
    vsphere storage appliance工作原理和实施
    vmware产品框架-计算中心,5.1更新等
    vcenter建立cluster
    vcenter 5.1安装亲历
    openfiler在esxi下的安装配置
    升级华为s2016
    ubuntu下配置华为交换机s2016
    Fibre Channel address weaknesses
    vsphere HA内幕变化
  • 原文地址:https://www.cnblogs.com/chanme/p/3894277.html
Copyright © 2020-2023  润新知