And And And【2019西安邀请赛】【点分治】

题目链接


A tree is a connected graph without cycles. You are given a rooted tree with nn nodes, labeled from 1 to n1ton. The tree is rooted at node 11. The parent of the ii-th node is f_{a_i}fai​​. The edge weight between the ii-th node and f_{a_i}fai​​ is w_iwi​

  • E(u, v)E(u,v) is a set of all the nodes through a path which is from uu to vv, including uu and vv. For example,

E(5,3) = \{5, 2, 1, 3\}, E(4,6) = \{4, 3, 6\}, E(2,5) = \{2,5\}E(5,3)={5,2,1,3},E(4,6)={4,3,6},E(2,5)={2,5}

  • X(u, v)X(u,v) represents the XOR of all edge weights on the path from uu to vv

For example, in the case given above,

X(1,5) = 1X(1,5)=1 ⁡xorxor 1=01=0,X(4,6) = 1X(4,6)=1 ⁡xorxor 3=23=2,X(2,5) = 1X(2,5)=1,X(3,5) = 2X(3,5)=2 xorxor 11 xorxor 11 =2=2⁡You need to calculate the answer to the following formula:

\displaystyle\sum_{u=1}^n \displaystyle\sum_{v=1}^n \displaystyle\sum_{u' \in E(u,v)} \displaystyle\sum_{v' \in E(u,v)} [u < v][ u' < v'][X(u',v')=0]u=1∑n​v=1∑n​u′∈E(u,v)∑​v′∈E(u,v)∑​[u<v][u′<v′][X(u′,v′)=0]

The answer modulo 10000000071000000007

  • XOR is equivalent to '^' in c / c++ / java / python. If both bits in the compared position of the bit patterns are 00 or 11, the bit in the resulting bit pattern is 00, otherwise 11.

Input

Each test file contains a single test case. In each test file:

The first line contains one integer n(1 \le n \le 10^5)n(1≤n≤105) — the number of nodes in the tree.

Then n - 1n−1 lines follow. ii-th line contains two integers f_{a_i}(1 \le f_{a_i} < i)fai​​(1≤fai​​<i), w_i(0 \le w_i \le 10^{18})wi​(0≤wi​≤1018) —The parent of the ii-th node and the edge weight between the ii-th node and f_{a_i} (ifai​​(i start from 2)2).

Output

Print a single integer — the answer of this problem, modulo 1000000007.


  题意是这样的:一个由N个点组成的树,我们要询问是这样的,假如有一条链的异或值为0,也就是代表着所有该链上的边的值异或起来为0,然后求所有包含这条链的链的个数,当然,可以重复出现链。

主要就是求这样的一个东西。

  思路:当然,我们这里先不讲树形dp的解法(当然是因为我还没有解出来的缘故),先讲讲点分治。

  首先的话,就是要避免重复,我们将一颗树不断的向下分治,首先就必须要满足分治过后的答案是可以合成起来的。在这里,我们从一个点(子树的重心)出发,以它为核心开始分割,然后就变成了我们现在访问到的点到已有点的答案之和了,不存在重复,所以就无需减去什么了。

  只是这里有个重点需要处理的内容,就是假如从该点出发,异或到某个点的时候值为0了,这时候需要把这个答案加上,因为当我们分治的时候,重心的那个点是没有计算在内的,假如有它的答案,依然是要算进去的。

  还有就是,假如从一个点开始分治的时候,两边的子树某到该点的异或值为0,我们不仅要算上述的答案还是要去算在已有子树中的为0的答案求和。

  最后,别忘了要去求一个mod。

给一组测试样例,方便理解(囊括了上面基本的内容):

10
1 1
1 1
2 2
3 2
4 1
4 1
5 1
5 2
8 1
ans:58

My Code

#include <iostream>
#include <cstdio>
#include <cmath>
#include <string>
#include <cstring>
#include <algorithm>
#include <limits>
#include <vector>
#include <stack>
#include <queue>
#include <set>
#include <map>
#include <unordered_map>
#define lowbit(x) ( x&(-x) )
#define pi 3.141592653589793
#define e 2.718281828459045
#define INF 0x3f3f3f3f
#define efs 1e-6
#define HalF (l + r)>>1
#define lsn rt<<1
#define rsn rt<<1|1
#define Lson lsn, l, mid
#define Rson rsn, mid+1, r
#define QL Lson, ql, qr
#define QR Rson, ql, qr
#define myself rt, l, r
using namespace std;
typedef double lb;
typedef unsigned long long ull;
typedef long long ll;
const int maxN = 1e5 + 7;
const ll mod = 1e9 + 7;
int pre[maxN], head[maxN], cnt, rt;
bool vis[maxN];
ll num_son[maxN], son[maxN], siz[maxN], dis[maxN], ans, N, all, mx;
unordered_map<ll, ll> mp;
struct Eddge
{
    int nex, to; ll val;
    Eddge(int a=-1, int b=0, ll c=0):nex(a), to(b), val(c) {}
}edge[maxN<<1];
inline void addEddge(int u, int v, ll w)
{
    edge[cnt] = Eddge(head[u], v, w);
    head[u] = cnt++;
}
inline void _add(int u, int v, ll w) { addEddge(u, v, w); addEddge(v, u, w); }
void pre_dfs(int u, int fa)
{
    pre[u] = fa;
    siz[u] = 1;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(v == fa) continue;
        pre_dfs(v, u);
        siz[u] += siz[v];
    }
}
int fath[maxN];
void findroot(int u, int fa)
{
    num_son[u] = 1; son[u] = 0;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v] || v == fa) continue;
        findroot(v, u);
        num_son[u] += num_son[v];
        if(num_son[v] > son[u]) son[u] = num_son[v];
    }
    son[u] = max(son[u], all - num_son[u]);
    if(son[u] < mx) { mx = son[u]; rt = u; }
}
struct node
{
    int id; ll val;
    node(int a=0, ll b=0):id(a), val(b) {}
}Stap[maxN];
int Stop;
void get_dis(int u, int fa)
{
    Stap[++Stop] = node(u, dis[u]);
    fath[u] = fa;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v] || v == fa) continue;
        dis[v] = dis[u] ^ edge[i].val;
        get_dis(v, u);
    }
}
void solve(int u)
{
    mp.clear();
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v]) continue;
        Stop = 0;
        dis[v] = edge[i].val;
        get_dis(v, u);
        for(int j=1, id; j<=Stop; j++)
        {
            id = Stap[j].id;
            if(fath[id] == pre[id])
            {
                ans = (ans + mp[Stap[j].val] * siz[id]) % mod;
                if(!Stap[j].val)
                {
                    if(pre[v] == fath[v]) ans = (ans + siz[id] * (N - siz[v])) % mod;
                    else ans = (ans + siz[id] * siz[u]) % mod;
                }
            }
            else
            {
                ans = (ans + mp[Stap[j].val] * (N - siz[fath[id]])) % mod;
                if(!Stap[j].val)
                {
                    if(pre[v] == fath[v]) ans = (ans + ((ll)N - siz[fath[id]]) * (N - siz[v])) % mod;
                    else ans = (ans + (N - siz[fath[id]]) * siz[u]) % mod;
                }
            }
        }
        for(int j=1, id; j<=Stop; j++)
        {
            id = Stap[j].id;
            if(fath[id] == pre[id])
            {
                mp[Stap[j].val] = (mp[Stap[j].val] + siz[id]) % mod;
            }
            else
            {
                mp[Stap[j].val] = (mp[Stap[j].val] + (N - siz[fath[id]])) % mod;
            }
        }
    }
}
void divide(int u)
{
    vis[u] = true;
    solve(u);
    ll totsiz = all;
    for(int i=head[u], v; ~i; i=edge[i].nex)
    {
        v = edge[i].to;
        if(vis[v]) continue;
        mx = INF; rt = 0;
        all = num_son[v] > num_son[u] ? totsiz - num_son[u] : num_son[v];
        findroot(v, 0);
        divide(rt);
    }
}
inline void init()
{
    cnt = 0; ans = 0; all = N; mx = INF;
    for(int i=1; i<=N; i++) head[i] = -1;
    for(int i=1; i<=N; i++) vis[i] = false;
}
int main()
{
    scanf("%lld", &N);
    init();
    for(int i=2, uu; i<=N; i++)
    {
        ll ww;
        scanf("%d%lld", &uu, &ww);
        _add(uu, i, ww);
    }
    pre_dfs(1, 0);
    findroot(1, 0);
    divide(rt);
    printf("%lld\n", ans);
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Wuliwuliii

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值