zoukankan      html  css  js  c++  java
  • 题解 P3899 【[湖南集训]谈笑风生】

    Luogu智能推荐给我搞的这个题啊,亦可赛艇!

    题目链接

    Solution [湖南集训]谈笑风生

    题目大意:和Wallace谈笑风生,给定一棵有根树,多次询问给定点(p)和限制(k),求有多少对有序三元组((p,b,c))满足(p,b)均为(c)的祖先且(p,b)间距离不超过(k)

    主席树,树上差分


    分析:

    首先我们分类讨论一下

    如果点(b)在点(p)上方时,有(min(dep[p] - 1,k) imes(siz[p]-1)),(dep)表示深度,(siz)表示子树大小,乘法原理显然

    关键是当点(b)在点(p)子树内是,对于一个确定的点(b),显然点(c)可以选择的数量就是(siz[b]-1)

    问题变成了,给定一棵树,每个点有一个点权,求一个点子树内与它距离不超过(k)的点的权值之和

    首先我们如果以深度为下标建一棵线段树,假设我们知道一个点子树的线段树的话查询就是区间求和问题,但是暴力计算时空复杂度均无法承受

    我们考虑子树的性质,如果求(dfs)序的话,一棵子树内点的(dfs)序一定是连续的,因此我们可以用主席树来计算,差分即可得到一个点子树的线段树

    #include <cstdio>
    #include <cctype>
    #include <vector>
    using namespace std;
    const int maxn = 3e5 + 100;
    typedef long long ll;
    inline int read(){
    	int x = 0;char c = getchar();
    	while(!isdigit(c))c = getchar();
    	while(isdigit(c))x = x * 10 + c - '0',c = getchar();
    	return x;
    }
    namespace ST{
    	const int maxnode = maxn * 30;
    	struct Node{
    		int ls,rs;
    		ll val;
    	}tree[maxnode];
    	int root[maxn],tot;
    	inline void pushup(int root){tree[root].val = tree[tree[root].ls].val + tree[tree[root].rs].val;}
    	inline void add(int last,int &root,int pos,int val,int l = 1,int r = 3e5){
    		root = ++tot;
    		if(l == r){
    			tree[root].val = tree[last].val + val;
    			return;
    		}
    		int mid = (l + r) >> 1;
    		if(pos <= mid)tree[root].rs = tree[last].rs,add(tree[last].ls,tree[root].ls,pos,val,l,mid);
    		else tree[root].ls = tree[last].ls,add(tree[last].rs,tree[root].rs,pos,val,mid + 1,r);
    		pushup(root);
    	}
    	inline ll query(int last,int root,int a,int b,int l = 1,int r = 3e5){
    		if(a <= l && b >= r)return tree[root].val - tree[last].val;
    		int mid = (l + r) >> 1;ll res = 0;
    		if(a <= mid)res += query(tree[last].ls,tree[root].ls,a,b,l,mid);
    		if(b >= mid + 1)res += query(tree[last].rs,tree[root].rs,a,b,mid + 1,r);
    		return res;
    	}
    }using namespace ST;
    vector<int> G[maxn];
    inline void addedge(int from,int to){G[from].push_back(to);}
    int dep[maxn],dfn[maxn],rnk[maxn],siz[maxn],dfs_tot,n,q;
    inline void dfs(int u,int faz = -1){
    	siz[u] = dep[1] = 1;
    	dfn[u] = ++dfs_tot;
    	rnk[dfs_tot] = u;
    	for(int v : G[u]){
    		if(v == faz)continue;
    		dep[v] = dep[u] + 1;
    		dfs(v,u);
    		siz[u] += siz[v];
    	}
    }
    int main(){
    	n = read(),q = read();
    	for(int u,v,i = 1;i < n;i++)
    		u = read(),v = read(),addedge(u,v),addedge(v,u);
    	dfs(1);
    	for(int i = 1;i <= n;i++)
    		add(root[i - 1],root[i],dep[rnk[i]],siz[rnk[i]] - 1);
    	for(int a,k,i = 1;i <= q;i++){
    		a = read(),k = read();
    		ll ans = min(dep[a] - 1,k) * ll(siz[a] - 1);
    		ans += query(root[dfn[a]],root[dfn[a] + siz[a] - 1],dep[a] + 1,dep[a] + k);
    		printf("%lld
    ",ans);
    	}
    	return 0;
    }
    
  • 相关阅读:
    Redhat各个版本和内核对照
    Java8 lambda表达式总结
    conda 安装指定版本的指定包
    git初始化的几句shell
    MYsqli 绑定插入与查询实例
    按天去除重复数据,为0则取0,否则取最大的那个值
    存储过程,循环插入1000条记录
    主表如何统计在附表中的出现次数?
    Invalid argument supplied for foreach()
    二十、mysql mysqldump备份工具
  • 原文地址:https://www.cnblogs.com/colazcy/p/11840239.html
Copyright © 2011-2022 走看看