zoukankan      html  css  js  c++  java
  • ccpc2020长春站F题 Strange Memory

    dsu on tree

    题目链接

    点我跳转

    题目大意

    给定一棵包含 (n) 个节点的树,每个节点有个权值 (a_i)

    (∑_{i=1}^n∑_{j=i+1}^n[a_i⊕a_j=a_{lca(i,j)}](i⊕j).)

    解题思路

    题目保证了 (a_i ≠ 0) ,所以不存在 (a_u⊕a_v = a_u),即满足条件的(a_u ⊕ a_v = a_{lca(u,v)})(u , v) 一定在不同分支

    这点极大的简单化了本问题

    于是在以 (rt) 为根的子树中,对于节点 (u) ,满足条件的点的异或值为 (a_u ⊕ a_{rt})

    (u) 对答案产生的贡献只和 (u) 在二进制下每一位的数值有关系

    于是我们可以定义 (f_{ijk}) 表示异或值为 (i) 的数 , 它们在二进制下第 (j) 位为 (k) 的个数

    那么对于 (u) , 它的贡献可以这么算

    int x = a[u] ^ a[rt];
    if(x <= 1000000) // a[i] <= 1e6
    {
    	for(int i = 17 ; i >= 0 ; i --)
    	{
    		int k = u >> i & 1;
    		ans += (1LL << i) * f[x][i][k ^ 1]; 
    	}
    }
    

    到这本题就差不多结束了

    别忘了一个分支内的任意节点不能相互影响,所以需要先对一个分支统计完贡献后,再添加它的信息

    AC_Code

    #include<bits/stdc++.h>
    #define rep(i , a , b) for(int i = a ; i <= b ; i ++)
    #define per(i , b , a) for(int i = b ; i >= a ; i --)
    #define ll long long
    #define pb push_back
    #define fi first
    #define se second
    using namespace std; 
    const int N = 1e5 + 10 , M = 1e6 + 10;
    struct Edge{
    	int nex , to;
    }edge[N << 2];
    int head[N] , TOT;
    void add_edge(int u , int v)
    {
    	edge[++ TOT].nex = head[u];
    	edge[TOT].to = v;
    	head[u] = TOT;
    }
    int dep[N] , sz[N] , hson[N] , HH;
    int a[N] , f[M][20][2];
    ll ans;
    void dfs(int u , int far)
    {
    	sz[u] = 1;
    	dep[u] = dep[far] + 1;
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far) continue ;
    		dfs(v , u);
    		sz[u] += sz[v];
    		if(sz[v] > sz[hson[u]]) hson[u] = v;
    	}
    }
    void change(int u , int far , int val)
    {
    	for(int i = 17 ; i >= 0 ; i --) f[a[u]][i][u >> i & 1] += val;
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far || v == HH) continue ;
    		change(v , u , val); 
    	}
    } 
    void calc(int u , int far , int rt)
    {
    	int x = a[u] ^ a[rt];
    	if(x <= 1000000)
    	{
    		for(int i = 17 ; i >= 0 ; i --)
    		{
    			int k = u >> i & 1;
    			ans += (1LL << i) * f[x][i][k ^ 1]; 
    		}
    	}
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far || v == HH) continue ;
    		calc(v , u , rt);
    	}
    }
    void dsu(int u , int far , int op)
    {
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to;
    		if(v == far || v == hson[u]) continue ;
    		dsu(v , u , 0);
    	}
    	if(hson[u]) dsu(hson[u] , u , 1) , HH = hson[u];
    	for(int i = head[u] ; i ; i = edge[i].nex)
    	{
    		int v = edge[i].to ;
    		if(v == far || v == HH) continue ;
    		calc(v , u , u) , change(v , u , 1);	
    	} 
    	HH = 0;
    	for(int i = 17 ; i >= 0 ; i --) f[a[u]][i][(u >> i) & 1] ++ ;
    	if(!op) change(u , far , -1);	
    }
    signed main()
    {
    	ios::sync_with_stdio(false);
    	int n ;
    	cin >> n;
    	rep(i , 1 , n) cin >> a[i];
    	rep(i , 2 , n)
    	{
    		int u , v;
    		cin >> u >> v;
    		add_edge(u , v) , add_edge(v , u);	
    	} 
    	dfs(1 , 0);
    	dsu(1 , 0 , 0);
    	cout << ans << '
    ';
    	return 0;
    }
    
  • 相关阅读:
    【JavaScript】函数(未完全)
    Spring集成Jersey开发(附demo)
    Tomcat中work目录的作用
    Lucene全文检索(一)
    JS放大镜特效(兼容版)
    S2SH整合
    EL表达式
    JSP和JavaBean
    Cookie和Session
    request对象和response对象
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/14028298.html
Copyright © 2011-2022 走看看