HDU 4916 Count on the path

题意:

给定一棵树和m个询问  每个询问要求回答不在u和v两节点所形成的路径上的点的最小标号

思路:

一开始以为是LCA…  不过T了好几次…  后来发现不用LCA也可做

考虑每个询问u和v  如果他们的lca不是1  则1一定是答案  不过求lca会T  那么我们只需要在遍历树的时候给节点染色  染的颜色就是1的儿子的颜色  如果x这个点在y的子树中(y是1的儿子)那么他的颜色就是y

染完色后我们考虑答案是如何构成的

如图所示  答案即是  红色  蓝色  绿色的子树中节点的最小值  那么我们只需要分开三部分求解即可

定义f[u][x]表示以u为根的子树中第x大的节点标号  这个可以通过树形dp求解  有了这个就可以解决绿色和红色的部分

定义g[u]表示u节点上面到1的路径中旁侧的子树的最小节点标号  即图中蓝色部分  也可以利用f做树形dp求解

注意:

题目中不让蓝色部分包含绿色部分  也不把绿色部分放在红色部分中考虑的原因就是u和v节点中的一个可能是1

由于我写的是dfs  杭电会爆栈  所以记得加栈  并用C++提交

代码:

#pragma comment(linker, "/STACK:102400000,102400000")
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 1000010

int f[N][4], g[N], col[N], head[N];
int n, m, color, tot, ans;
struct edge {
    int v, next;
} ed[N * 2];

int d(int a, int b) {
    if (a < b)
        return a;
    return b;
}

void add(int u, int v) {
    ed[tot].v = v;
    ed[tot].next = head[u];
    head[u] = tot++;
}

void dfs1(int u, int fa) {
    int i, v;
    if (u != 1)
        col[u] = color;
    for (i = head[u]; ~i; i = ed[i].next) {
        v = ed[i].v;
        if (u == 1)
            color = v;
        if (v != fa) {
            dfs1(v, u);
            f[u][3] = d(v, f[v][0]);
            sort(f[u], f[u] + 4);
        }
    }
}

void dfs2(int u, int fa) {
    if (fa != 1) {
        if (d(u, f[u][0]) != f[fa][0])
            g[u] = f[fa][0];
        else
            g[u] = f[fa][1];
        if (g[u] > g[fa])
            g[u] = g[fa];
    }
    int i, v;
    for (i = head[u]; ~i; i = ed[i].next) {
        v = ed[i].v;
        if (v != fa)
            dfs2(v, u);
    }
}

int main() {
    int i, j, u, v;
    while (~scanf("%d%d", &n, &m)) {
        for (i = 1; i <= n; i++) {
            f[i][0] = f[i][1] = f[i][2] = f[i][3] = g[i] = N;
            head[i] = -1;
        }
        col[1] = 1;
        tot = ans = 0;
        for (i = 1; i < n; i++) {
            scanf("%d%d", &u, &v);
            add(u, v);
            add(v, u);
        }
        dfs1(1, 1);
        dfs2(1, 1);
        for (i = 1; i <= m; i++) {
            scanf("%d%d", &u, &v);
            u ^= ans;
            v ^= ans;
            if (col[u] == col[v]) {
                if (u == 1 || v == 1)
                    ans = 2;
                else
                    ans = 1;
            } else {
                if (u > v)
                    swap(u, v);
                ans = min(f[v][0], min(g[u], g[v]));
                if (u != 1) {
                    ans = min(ans, f[u][0]);
                    v = min(col[v], f[col[v]][0]);
                    u = min(col[u], f[col[u]][0]);
                    for (j = 0; j < 3; j++) {
                        if (f[1][j] != u && f[1][j] != v) {
                            ans = min(ans, f[1][j]);
                            break;
                        }
                    }
                } else {
                    v = min(col[v], f[col[v]][0]);
                    for (j = 0; j < 3; j++) {
                        if (f[1][j] != v) {
                            ans = min(ans, f[1][j]);
                            break;
                        }
                    }
                }
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}

HDU 4916 Count on the path,布布扣,bubuko.com

时间: 2024-10-13 05:15:30

HDU 4916 Count on the path的相关文章

【树形DP】 HDU 4916 Count on the path

通道 题意:一棵树,求不经过路径的最小标号 代码: #include <iostream> #include <cstring> #include <string> #include <vector> #include <cstdio> #include <cmath> #include <algorithm> using namespace std; #define maxn 1005000 #define inf 0x

hdu 1705 Count the grid(皮克定理)

题目链接:hdu 1705 Count the grid 题意: 给定一个三角形三点坐标,问三角形内有多少个坐标均为整数的点. 题解: 给定顶点坐标均是整点(或正方形格点)的简单多边形,皮克定理说明了其面积 S 和内部格点数目 n.边上格点数目 s 的关系:S = n +s/2+1 三角形两向量叉积/2=面积. 向量上整数点数为gcd(v.x,v.y)(此公式对于一条边上的结果不准确,但是三条边加在一起的和是准确的) 1 #include<bits/stdc++.h> 2 #define F(

HDU 4588 Count The Carries(找规律,模拟)

题目 大意: 求二进制的a加到b的进位数. 思路: 列出前几个2进制,找规律模拟. #include <stdio.h> #include <iostream> #include <algorithm> #include <string.h> #include <math.h> #include <stack> #include <vector> using namespace std; int main() { int

hdu 3336 Count the string

Count the stringTime Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 4239    Accepted Submission(s): 1977 Problem Description It is well known that AekdyCoin is good at string problems as well as num

HDU 4588 Count The Carries 数位DP || 打表找规律

2013年南京邀请赛的铜牌题...做的很是伤心,另外有两个不太好想到的地方....a 可以等于零,另外a到b的累加和比较大,大约在2^70左右. 首先说一下解题思路. 首先统计出每一位的1的个数,然后统一进位. 设最低位为1,次低位为2,依次类推,ans[]表示这一位上有多少个1,那么有 sum += ans[i]/2,ans[i+1] += ans[i]/2; sum即为答案. 好了,现在问题转化成怎么求ans[]了. 打表查规律比较神奇,上图不说话. 打表的代码 #include <algo

Count on the path

Count on the path Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description bobo has a tree, whose vertices are conveniently labeled by 1,2,…,n. Let f(a,b) be the minimum of vertices not on the path bet

hdu 3336 Count the string(KMP)

一道应用kmp算法中next数组的题目 这其中vis[i]从1加到n vis[i]=[next[i]]+1; #include<string.h> #include<stdlib.h> #include<stdio.h> #include<iostream> #include<algorithm> using namespace std; char s[200005]; int b; int next[200005]; int vis[20000

HDU 4916 树形dp

Count on the path Time Limit: 5000/2500 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 92    Accepted Submission(s): 10 Problem Description bobo has a tree, whose vertices are conveniently labeled by 1,2,-,n. Let

hdu 1812 Count the Tetris polya计数

哈哈哈,简单polya,公式自己推导. 不过这题需要用到大数,很久没写Java,调了好久. import java.math.*; import java.util.*; import java.io.*; public class Main{ public static void main(String args[]){ Scanner cin=new Scanner(System.in); int n; BigInteger c; while(cin.hasNextInt()) { BigI