• $NOIP2016$天天爱跑步


    (NOIP2016)天天爱跑步

    (™)(NOIP)近几年中最难的一道……

    先看一下部分分,有起点终点为根节点的分值,想到拆路径,对于路径((S,T)),拆为((S,LCA))((T,LCA))

    首先明确一点,可能有多条路径有相同的起点,(LCA)或终点。

    先考虑((S,LCA))这一半,一条路径只会对路径上的点产生贡献,不妨设有一个点(x)在这一半上。

    则这条路径对(x)有贡献,当且仅当满足(d[u]=w[x]+d[x])时,发现对于一个点(观察员),(w[x]+d[x])为定值。

    对于一个点(x),一条路径对其有贡献当且仅当这条路径的(LCA)(x)或这条路径仅有一个端点在(x)的子树中(这样的路径(LCA)(x)之上)

    如图,蓝色和绿色的路径会产生贡献,而红色则不会。所以我们可以(Dfs)统计答案,即查看有多少个在(x)的子树中的路径起点的(d[u])等于(w[x]+d[x]),这样统计出的答案只会多不会少,我们考虑如何去掉多余的答案。

    先看一下实现过程,先开一个(Bag[])记录像(d[u])这样的值,在(x)的子树中处理完之后只要提出(Bag[w[x]+d[x]])的答案即可,但这样我们会发现会统计进起点根本不是(x)子树中的路径,因此我们先记录下到(x)(Bag[w[x]+d[x]])的值,在处理完子树之后再将(Bag[w[x]+d[x]])的值和原值相减即可。

    但是还有像红色这样的路径会被考虑,所以在跑(x)的子树中的节点(设为(y))时,我们将以(y)(LCA)的路径从桶中减去即可,这样我们统计到的答案就没有多余的了。

    同样,考虑((T,LCA))时,我们要满足的式子为:(w[x]-d[x]=d[u]-2*d[LCA])即可。(注意这里可能出现负数,我们加上(N_{max}))即可。

    还有一点,在计算(x)的答案时,不要忘了以(x)为路径起点或终点时可以对上面产生贡献,要同时更新(Bac)中的值。

    做完之后,所有路径(LCA)的点答案会被算两次,要减掉

    #include<bits/stdc++.h>
    using namespace std;
    #define int long long
    inline int read()
    {
        int f=1,w=0;char x=0;
        while(x<'0'||x>'9') {if(x=='-') f=-1; x=getchar();}
        while(x!=EOF&&x>='0'&&x<='9') {w=(w<<3)+(w<<1)+(x^48);x=getchar();}
        return w*f;
    }
    const int N=300010,M=1000010;
    int n,m,num_edge,MD;
    int las[N][21],ans[N],boki[N];
    vector<int> Lex[N],End[N],LCA[N];
    int head[N],Dep[N],W[N],Bag[M];
    struct Edge{int next,to;} edge[N<<1];
    struct Group{int from,to,lca;} Ply[N];
    inline void Add(int from,int to)
    {
    	edge[++num_edge].next=head[from];
    	edge[num_edge].to=to;
    	head[from]=num_edge;
    }
    inline void Dfs(int pos,int fa)
    {
    	las[pos][0]=fa;Dep[pos]=Dep[fa]+1;
    	for(int i=0;i<20;i++) las[pos][i+1]=las[las[pos][i]][i];
    	for(int i=head[pos];i;i=edge[i].next)
    		if(edge[i].to!=fa) Dfs(edge[i].to,pos);
    }
    inline int LCA_Ask(int u,int v)
    {
    	if(Dep[u]<Dep[v]) swap(u,v);
    	for(int i=20;i>=0;i--) if(Dep[v]<=Dep[u]-(1<<i)) u=las[u][i];
    	if(u==v) return u;
    	for(int i=20;i>=0;i--) if(las[u][i]!=las[v][i]) u=las[u][i],v=las[v][i];
    	return las[u][0];
    }
    inline void Dfs_For_From(int pos,int fa)//统计路径(S,LCA)的答案
    {
    	int Num=Dep[pos]+W[pos],Now;if(Num<=MD) Now=Bag[Num];
    	for(int i=head[pos];i;i=edge[i].next)
    		if(edge[i].to!=fa) Dfs_For_From(edge[i].to,pos);
    	Bag[Dep[pos]]+=boki[pos];//以pos为起点的路径对上面的点产生的贡献
        if(Num<=MD) ans[pos]=Bag[Num]-Now;
    	for(int i=0;i<(int)Lex[pos].size();i++) Bag[Dep[Lex[pos][i]]]--;//以pos为LCA的路径对上面的点不会在产生贡献了
    }
    inline void Dfs_For_To(int pos,int fa)//统计路径(LCA,T)的答案
    { 
    	int Num=Dep[pos]-W[pos]+N,Now;Now=Bag[Num];
    	for(int i=head[pos];i;i=edge[i].next)
    		if(edge[i].to!=fa) Dfs_For_To(edge[i].to,pos);
    	for(int i=0;i<(int)End[pos].size();i++) Bag[N+End[pos][i]]++;//以pos为终点的路径对上面的点产生的贡献
    	ans[pos]+=Bag[Num]-Now;
    	for(int i=0;i<(int)LCA[pos].size();i++) Bag[N+LCA[pos][i]]--;//以pos为LCA的路径对上面的点不会在产生贡献了
    }
    main(){
    #ifndef ONLINE_JUDGE
        freopen("A.in","r",stdin);//Ans=2 0 0 1 1
    	//freopen("B.in","r",stdin);//Ans=1 2 1 0 1
    	freopen("A.out","w",stdout);
    #endif
    	n=read(),m=read();MD=-1;
    	for(int i=1,u,v;i<n;i++)
    		u=read(),v=read(),Add(u,v),Add(v,u);
    	for(int i=1;i<=n;i++) W[i]=read();Dfs(1,0);
    	for(int i=1;i<=n;i++) MD=max(MD,Dep[i]);
    	for(int i=1;i<=m;i++)
    	{
    		Ply[i].from=read(),Ply[i].to=read();boki[Ply[i].from]++;
    		Ply[i].lca=LCA_Ask(Ply[i].from,Ply[i].to);
    		Lex[Ply[i].lca].push_back(Ply[i].from);
    		End[Ply[i].to].push_back(2*Dep[Ply[i].lca]-Dep[Ply[i].from]);
    		LCA[Ply[i].lca].push_back(2*Dep[Ply[i].lca]-Dep[Ply[i].from]);
    	}
    	Dfs_For_From(1,0);memset(Bag,0,sizeof(Bag));Dfs_For_To(1,0);
    	for(int i=1;i<=m;i++)
    		if(Dep[Ply[i].from]-Dep[Ply[i].lca]==W[Ply[i].lca])
    			ans[Ply[i].lca]--;//减去路径LCA答案重复计算的部分
    	for(int i=1;i<=n;i++) printf("%lld ",ans[i]);
    }
    
  • 相关阅读:
    jquery的一些函数
    int ,long,long long范围
    DMZ
    C读取文件(如果你不知道文件内容SIZE)
    flot画饼图
    flot绘制折线图
    JS操作select相关方法:新增 修改 删除 选中 清空 判断存在
    JS-字符串操作
    websGetVar函数
    AJAX之XMLHTTPRequest对象
  • 原文地址:https://www.cnblogs.com/wo-shi-zhen-de-cai/p/11319754.html
Copyright © 2020-2023  润新知