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;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章