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

    P3899 [湖南集训]谈笑风生

    solve

    通过观察我们发现,a是固定不动的,而b距离a不超过k

    则b有两种情况。

    ((i))b在a的上方

    (b)(a)的距离最大为$ min(deep[a],k)$

    (c)就是(a)子树的任意一点。

    则对答案的贡献就是$ min(deep[a],k)* (size[a]-1) $

    ((ii))b是a的下方

    那我们b是a子树上距离(a)不超过k也就是深度差不超过k的一个点

    (c)就是(b)子树上的一个点

    对答案的贡献就是把所有可能的(size[b])加起来

    我们以(deep[x])为下标,(size[x])为权值建主席树,就可以统计出(sum)总和了。

    注意一点,数据比较大,要开long long

    code

    #include<iostream>
    #include<cmath>
    #include<cstdio>
    using namespace std;
    const int maxn=600005;
    typedef long long LL;
    int N,Q,son[maxn],nxt[maxn],lnk[maxn],cnt,deep[maxn],size[maxn],r[maxn],tot,q[maxn],l[maxn],sz,root[maxn];
    struct data{
    	int l,r;
    	LL sum;
    }tr[maxn*32];
    inline int read(){
    	int ret=0,f=1;char ch=getchar();
    	while(ch<'0'||ch>'9'){if(ch=='-')f=-f;ch=getchar();}
    	while(ch<='9'&&ch>='0')ret=ret*10+ch-'0',ch=getchar();
    	return ret*f;
    }
    int add_e(int x,int y){son[++cnt]=y;nxt[cnt]=lnk[x];lnk[x]=cnt;}
    void dfs(int u,int fa){
    	l[u]=++tot;deep[u]=deep[fa]+1;q[tot]=u;size[u]=1;
    	for(int j=lnk[u];j;j=nxt[j]){
    		if(son[j]==fa)continue;
    		dfs(son[j],u);size[u]+=size[son[j]];
    	}
    	r[u]=tot;
    }
    void insert(int &x,int l,int r,int pos,int val){
    	tr[++sz]=tr[x];x=sz;
    	tr[x].sum+=(LL)val;
    	if(l==r)return ;
    	int mid=(l+r)>>1;
    	if(pos<=mid)insert(tr[x].l,l,mid,pos,val);
    	else insert(tr[x].r,mid+1,r,pos,val);
    }
    void update(int x){
    	int l=tr[x].l,r=tr[x].r;
    	tr[x].sum=tr[l].sum+tr[r].sum;
    }
    LL query(int i,int j,int l,int r,int ll,int rr){
    	if(ll<=l&&r<=rr)return tr[j].sum-tr[i].sum;
    	int mid=(l+r)>>1;
    	LL ans=0;
    	if (ll<=mid)ans+=query(tr[i].l,tr[j].l,l,mid,ll,rr);
    	if (rr>mid)ans+=query(tr[i].r,tr[j].r,mid+1,r,ll,rr);
    	return ans;
    } 
    int main(){
    	freopen("3653.in","r",stdin);
    	freopen("3653.out","w",stdout);
    	N=read();Q=read();
    	for(int i=1;i<N;i++){
    		int x=read(),y=read();
    		add_e(x,y);add_e(y,x);
    	}
    	dfs(1,0);
    	for(int i=1;i<=N;i++)root[i]=root[i-1],insert(root[i],1,N,deep[q[i]],size[q[i]]-1);
    	for(int i=1;i<=Q;i++){
    		int x=read(),k=read();
    		LL t=query(root[l[x]],root[r[x]],1,N,deep[x]+1,deep[x]+k);
    		int len=min(k,deep[x]-1);
    		printf("%lld
    ",t+(LL)len*(LL)(size[x]-1));
    	}
    	return 0;
    }
    
  • 相关阅读:
    [国嵌攻略][113][字符设备驱动模型]
    [国嵌攻略][112][使用字符设备驱动]
    [国嵌攻略][111][硬件访问技术]
    [国嵌攻略][110][驱动开发概述]
    [国嵌攻略][109][Linux系统调用]
    [国嵌攻略][108][Linux内核链表]
    [国嵌攻略][107][Linux进程管理子系统]
    [国嵌攻略][106][Linux内存管理子系统]
    关于坐标转换!重要!(转)
    【总结整理】关于切图工具及自定义地图
  • 原文地址:https://www.cnblogs.com/martian148/p/13305833.html
Copyright © 2011-2022 走看看