• 【BZOJ3653】谈笑风生(长链剖分)


    【BZOJ3653】谈笑风生(长链剖分)

    题面

    BZOJ
    洛谷
    权限题啊。。。。

    题解

    首先根据题目给的条件,发现(a,b)都要是(c)的父亲。
    所以这三个点是树上的一条深度单增的链。
    因为(a,b)之间距离不超过(k),并且(a)被钦定了,所以只有两种情况:
    一种是(a)(b)的祖先,贡献是(sum_b size[b]-1),也就是所有(b)可以选择的点的子树和。
    另外一种(b)(a)的祖先,贡献是(sum_b size[a]-1),钦定一个(b)之后,(c)可以在(a)的子树中任选。
    第二种情况很简单,因为(size[a])是定值,并且每个点的父亲是唯一的,所以第二部分很容易算。
    困难的是第一部分,然而依旧不难把。。。
    方法很多,比如说,你把(dfs)序和深度看成(x,y)轴,这样子就是二维数点,直接主席树。
    或者说直接点分治也可以。

    当然,既然想写长链剖分,那就当然要用长链剖分来做啊。
    我们发现,所有的值都由重儿子向后挪动一位得来,而我们要求的东西需要维护一个区间和。
    这样子很不好用前缀和来做,所以我们可以用一个后缀和啊!
    这样子就很舒服了,直接维护后缀和,然后长链剖分转移,可以做到复杂度(O(n))

    #include<iostream>
    #include<cstdio>
    #include<cstdlib>
    #include<cstring>
    #include<cmath>
    #include<algorithm>
    #include<vector>
    using namespace std;
    #define ll long long
    #define MAX 300300
    inline int read()
    {
    	int x=0;bool t=false;char ch=getchar();
    	while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
    	if(ch=='-')t=true,ch=getchar();
    	while(ch<='9'&&ch>='0')x=x*10+ch-48,ch=getchar();
    	return t?-x:x;
    }
    struct Ask{int id,k;};
    vector<Ask> p[MAX];
    struct Line{int v,next;}e[MAX<<1];
    int h[MAX],cnt=1;
    inline void Add(int u,int v){e[cnt]=(Line){v,h[u]};h[u]=cnt++;}
    ll tmp[MAX],*s[MAX],*id=tmp,ans[MAX];
    int md[MAX],dep[MAX],fa[MAX],hson[MAX],size[MAX];
    void dfs1(int u,int ff)
    {
    	md[u]=dep[u]=dep[ff]+1;fa[u]=ff;size[u]=1;
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==ff)continue;
    		dfs1(v,u);size[u]+=size[v];
    		if(md[v]>md[hson[u]])hson[u]=v;
    	}
    	if(hson[u])md[u]=md[hson[u]];
    }
    void dfs(int u)
    {
    	s[u][0]=size[u]-1;
    	if(hson[u])s[hson[u]]=s[u]+1,dfs(hson[u]),s[u][0]+=s[hson[u]][0];
    	for(int i=h[u];i;i=e[i].next)
    	{
    		int v=e[i].v;if(v==fa[u]||v==hson[u])continue;
    		s[v]=id;id+=md[v]-dep[v]+1;dfs(v);
    		for(int j=0;j<=md[v]-dep[v];++j)s[u][j+1]+=s[v][j];
    		s[u][0]+=s[v][0];
    	}
    	for(int i=p[u].size()-1;~i;--i)
    	{
    		int k=p[u][i].k,id=p[u][i].id;
    		ans[id]+=1ll*(size[u]-1)*min(dep[u]-1,k);
    		if(k>=md[u]-dep[u])ans[id]+=s[u][0]-size[u]+1;
    		else ans[id]+=s[u][0]-size[u]+1-s[u][k+1];
    	}
    }
    int n,Q;
    int main()
    {
    	n=read();Q=read();
    	for(int i=1;i<n;++i)
    	{
    		int u=read(),v=read();
    		Add(u,v);Add(v,u);
    	}
    	dfs1(1,0);
    	for(int i=1;i<=Q;++i)
    	{
    		int u=read(),k=read();
    		p[u].push_back((Ask){i,k});
    	}
    	s[1]=id;id+=md[1];dfs(1);
    	for(int i=1;i<=Q;++i)printf("%lld
    ",ans[i]);
    	return 0;
    }
    
    
  • 相关阅读:
    怎样改动、扩展并重写Magento代码
    解决Gradle minifyEnabled无法找到错误
    使用Hadoop的MapReduce与HDFS处理数据
    cmake 学习笔记(一)
    简单的日志系统
    WebStorm 7.0 注冊码
    DOS命令大全--具体解释
    SQL SERVER之数据查询
    闰年的定义
    Javascript作用域链
  • 原文地址:https://www.cnblogs.com/cjyyb/p/9477533.html
Copyright © 2020-2023  润新知