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;
    }
    
  • 相关阅读:
    ZOJ 2158 Truck History
    Knight Moves (zoj 1091 poj2243)BFS
    poj 1270 Following Orders
    poj 2935 Basic Wall Maze (BFS)
    Holedox Moving (zoj 1361 poj 1324)bfs
    ZOJ 1083 Frame Stacking
    zoj 2193 Window Pains
    hdu1412{A} + {B}
    hdu2031进制转换
    openjudge最长单词
  • 原文地址:https://www.cnblogs.com/StarRoadTang/p/14028298.html
Copyright © 2011-2022 走看看