zoukankan      html  css  js  c++  java
  • 杂题集萃[6]

    题目描述

    给出一棵 (N) 个节点的树,树上的每个节点都有一个权值 (A[i])
    (Q) 次询问,每次在树上选中两个点 (u,v),考虑所有在简单路径 (u,v) 上(包括 (u,v))的点构成的集合(S)
    求$$sum_{win S}{A[w]orDist(u,w)}$$
    其中 (Dist(u,w)) 为简单路径 (u,w)上的边数,(or)是按位或。

    输入描述:

    第一行两个整数 (N,Q)

    接下来一行 (N) 个整数,第 (i) 个为 (A[i])

    接下来的 (N−1) 行,每行两个整数 (u,v)。表示 (u,v) 之间有一条边。

    接下来的 (Q) 行,每行两个整数 (u,v)。表示一组询问。

    输出描述:

    一行一个整数,代表小N想知道的数的数量。

    • 输入

    5 2
    4 3 2 5 3
    1 2
    1 3
    3 4
    3 5
    2 5
    3 4
    
    • 输出

    13
    7
    

    数据范围:

    题解

    算法 1

    对于每组询问,遍历所有节点,看看它是不是在路径上,并计算答案。

    时间复杂度 (O(nq))。期望得分 (10) 分。

    算法 2

    由于可能询问的点对只有 (O(n^2)) 组,每次枚举 (u) 开始深搜。

    时间复杂度 (O(n^2))。期望得分 (20) 分。

    算法 3

    当树形态随机的时候,两个点之间期望只有 (O(log n)) 个点,暴力即可。

    时间复杂度 (O(Hq))。期望得分 (20) 分,结合算法 2,期望得分 (30) 分。

    算法 4

    (a_i<2) 的时,按位或只会对最后一位产生影响,即,当 (dist(w,u)) 为奇数且 (a_w=1) 时,答案需要减 (1)。于是只要倍增时顺便维护从每一个点 (t) 出发,向上 (2^i) 的距离之内,与 (t) 距离为奇数且点权为 (1) 的点的个数就行了。

    时间复杂度 (O(nlog n))。期望得分 (10) 分,结合算法 2、3,期望得分 (40) 分。

    算法 5

    类似的,可以分别考虑每一个二进制位对答案的贡献。即,对于位 (2^x),维护从每一个点 (t) 出发,向上 (2^i) 的距离之内,与 (t) 距离为 (d) 满足 (d mathbin{mathrm{and}} 2^x = 2^x) 且点权的二进制表示中包含 (2^x) 的点的个数就行了。

    由于路径有向上的部分,也有向下的部分,因此还需要维护满足 (d mathbin{mathrm{and}} 2^x = 0) 的点的个数在从 (v) 倍增的时候使用。

    时间复杂度 (O(nlog n log a_i)) 期望得分 (50)(60) 分。

    算法 6

    注意到并不需要对于每一个位分别维护点的个数和,只需要维护所有重叠的位的数位和就行了,于是乎可以少掉一个 (log)

    时间复杂度 (O(nlog n)) 期望得分 (100) 分。

    code

    #include<bits/stdc++.h>
    using namespace std;
    typedef long long ll;
    const int N=5e5+7;
    struct query{int x,y,id;}q[N];
    int n,Q,lg,a[N],dep[N],fa[N][20],cnt[N][20];
    ll fu[N][20],fd[N][20];
    vector<int>G[N];
    inline void dfs(int u){
    	for(int i=0;i<=lg;i++)cnt[u][i]=cnt[fa[u][0]][i]+!(a[u]&(1<<i));
    	for(int i=0;i<G[u].size();i++)
    	if(G[u][i]!=fa[u][0])fa[G[u][i]][0]=u,dep[G[u][i]]=dep[u]+1,dfs(G[u][i]);
    }
    inline int lca(int u,int v){
    	if(dep[u]<dep[v])swap(u,v);
    	int t=dep[u]-dep[v];
    	for(int i=lg;~i;i--)
    	if(t&(1<<i))u=fa[u][i];
    	if(u==v)return u;
    	for(int i=lg;~i;i--)
    	if(fa[u][i]!=fa[v][i])u=fa[u][i],v=fa[v][i];
    	return fa[u][0];
    }
    inline ll query1(int u,int v){
    	ll ans=0;
    	int t=dep[u]-dep[v];
    	for(int i=lg;~i;i--)
    	if(t&(1<<i))
    	ans+=fu[u][i],u=fa[u][i],ans+=(1ll<<i)*(cnt[u][i]-cnt[v][i]);
    	return ans;
    }
    inline ll query2(int u,int d){
    	ll ans=0;int v=u;
    	for(int i=0;i<=lg;i++)
    	if(d&(1<<i))
    	ans+=fd[v][i]+(1ll<<i)*(cnt[u][i]-cnt[v][i]),v=fa[v][i];
    	return ans;
    }
    int main(){
    	scanf("%d%d",&n,&Q);
    	while((1<<lg)<n)lg++;
    	for(int i=1;i<=n;i++)scanf("%d",&a[i]);
    	for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),G[x].push_back(y),G[y].push_back(x);
    	dep[1]=1;
    	dfs(1);
    	for(int i=1;i<=n;i++)fu[i][0]=fd[i][0]=a[i];
    	for(int j=1;j<=lg;j++)
    	for(int i=1;i<=n;i++){
    		fa[i][j]=fa[fa[i][j-1]][j-1];
    		fu[i][j]=fu[i][j-1]+fu[fa[i][j-1]][j-1]+(1ll<<j-1)*(cnt[fa[i][j-1]][j-1]-cnt[fa[i][j]][j-1]);
    		fd[i][j]=fd[i][j-1]+fd[fa[i][j-1]][j-1]+(1ll<<j-1)*(cnt[i][j-1]-cnt[fa[i][j-1]][j-1]);
    	}
    	while(Q--){
    		int x,y,f,d;
    		scanf("%d%d",&x,&y);
    		f=lca(x,y);
    		d=dep[x]+dep[y]-dep[f]*2;
    		printf("%lld
    ",query1(x,fa[f][0])+query2(y,d+1)-query2(f,dep[x]-dep[f]+1));
    	}
    }
    
  • 相关阅读:
    只想能成为一个欢喜善良的人,别无所求。
    sickbaby 暗地病孩子
    objectc基础之二:property,assign,copy,retain,release
    Objectc基础之一:#import,NSLog(),数据类型
    Objectc基础之四:预定义,条件编译,数组
    初探NodeJs
    ActiveMQ安装与测试
    Objectc基础之三:面对对象开发@interface,@implementation
    iphoneCocos2D游戏开发之一:游戏术语大解析
    Nginx的gzip配置参数说明
  • 原文地址:https://www.cnblogs.com/Sparks-Pion/p/9696084.html
Copyright © 2011-2022 走看看