zoukankan      html  css  js  c++  java
  • P5002 专心OI

    P5002 专心OI - 找祖先

    给定一棵有根树((n leq 10000)),(M leq 50000) 次询问, 求以 (x)(LCA) 的点对个数


    错误日志: 看下面


    Solution

    设点 (u) 的子树大小为 (size[u])
    现询问以 (u)(LCA) 的点对个数
    (u) 的子节点为 (v_{1}, v_{2},...,v_{m})
    我们现在统计点对中一个点在 (v_{1}) 内的答案数
    一个点在 (v_{1}) 内, 另一个点要么是 (u) 要么在剩下的子节点子树内选一个
    所以总数为 (size[u] - size[v_{1}])
    乘法原理 (v_{1}) 子树中所有答案为 (size[v] * (size[u] - size[v]))
    每个子节点点都是这样
    最后加上一个 ((u, u)) 即可

    然后这样 (85pnts)
    看数据范围, 最不优情况 (O(NM))
    然后发现 (M > N)
    询问次数多于点个数?
    这提示我们像记忆化那样记下答案
    回头想想这样的复杂度为 (O(N)) , 这是一棵树, 边数和点数不会差太多, 复杂度有保障

    Code

    #include<iostream>
    #include<cstdio>
    #include<queue>
    #include<cstring>
    #include<algorithm>
    #define LL long long
    #define REP(i, x, y) for(LL i = (x);i <= (y);i++)
    using namespace std;
    LL RD(){
        LL out = 0,flag = 1;char c = getchar();
        while(c < '0' || c >'9'){if(c == '-')flag = -1;c = getchar();}
        while(c >= '0' && c <= '9'){out = out * 10 + c - '0';c = getchar();}
        return flag * out;
        }
    const LL maxn = 200019,INF = 1e9 + 19, M = 1e9 + 7;
    LL head[maxn],nume = 1;
    struct Node{
        LL v,dis,nxt;
        }E[maxn << 3];
    void add(LL u,LL v,LL dis){
        E[++nume].nxt = head[u];
        E[nume].v = v;
        E[nume].dis = dis;
        head[u] = nume;
        }
    LL num, root, na;
    LL size[maxn], fa[maxn];
    LL mem[maxn];
    void dfs(LL u, LL F){
    	size[u] = 1;
    	for(LL i = head[u];i;i = E[i].nxt){
    		LL v = E[i].v;
    		if(v == F)continue;
    		fa[v] = u;
    		dfs(v, u);
    		size[u] = (size[u] + size[v]) % M;
    		}
    	}
    void init(){
    	num = RD(), root = RD(), na = RD();
    	REP(i, 1, num - 1){
    		LL u = RD(), v = RD();
    		add(u, v, 1), add(v, u, 1);
    		}
    	dfs(root, -1);
    	}
    void solve(){
    	while(na--){
    		LL ans = 0, u = RD(), temp = size[u];
    		if(mem[u]){printf("%lld
    ", mem[u]);continue;}
    		for(LL i = head[u];i;i = E[i].nxt){
    			LL v = E[i].v;
    			if(v == fa[u])continue;
    			ans = (ans + ((size[v] * (temp - size[v])) % M + M) % M) % M;
    			temp = ((temp - size[v]) % M + M) % M;
    			}
    		ans = (ans * 2 + 1) % M;
    		mem[u] = ans;
    		printf("%lld
    ", ans);
    		}
    	}
    int main(){
    	init();
    	solve();
    	return 0;
    	}
    
  • 相关阅读:
    linux的一些命令
    Java中小数精确计算
    java中基本数据类型和包装类自动装箱和拆箱
    Python学习day14(内置函数二,匿名函数)
    Python学习day13(内置函数一)
    Python学习day12(生成器,列表/生成器推导式)
    Python学习day11(函数名本质,闭包及迭代器)
    Python学习day10(函数名称空间及嵌套)
    Python学习day9(函数初识)
    Python学习day8(文件操作)
  • 原文地址:https://www.cnblogs.com/Tony-Double-Sky/p/9910735.html
Copyright © 2011-2022 走看看