前缀和,LCA(CRB and Tree,HDU 5416)

来源:互联网 发布:linux怎么安装vmtools 编辑:程序博客网 时间:2024/05/17 01:59

首先要知道

树上最短路公式(树上两点间距离公式):

记dis[u]为根节点到u节点的距离。

dist(u,v) = dis[u] + dis[v] - 2 * dis[lca(u, v)]


如果距离的定义改为异或和。

那么公式就改为

dist(u,v) = dis[u] ^ dis[v]


剩下的问题就比较好解决了。


值得注意的是计算无序对的时候,有时不得不先计算出有序对然后再除以2。

比如(u,v)和(v,u)各计算了一次,所以要除以2。

但是如果(u,u)是一个合法的数据,那么它将只被计算一次,如果和其他数据一块除以2,那么将会得到错误的结果。

原理是矩阵的下三角的元素个数并不等于矩阵元素个数的一半。

解决办法是特殊考虑,让他计算两次或者单独计算。


WA了两发

读题:没问题

算法:没有算对无序对的个数。

实现:没问题

细节:总数可能会爆int

主要是算法和细节的问题。


代码

#include<stdio.h>#include<vector>#include<algorithm>#include<string.h>using namespace std;typedef long long ll;const int maxn = 100010;int num[maxn<<1];int N;vector<int>G[maxn];vector<int>W[maxn];int dp[maxn];int Q;int s;void read(){    memset(num,0,sizeof(num));    scanf("%d",&N);    for(int i=1;i<=N;i++)        G[i].clear(),W[i].clear();    int u,v,w;    for(int i=1;i<N;i++)    {        scanf("%d %d %d",&u,&v,&w);        G[u].push_back(v);        G[v].push_back(u);        W[u].push_back(w);        W[v].push_back(w);    }}void dfs(int u,int f){    num[dp[u]]++;    for(int i=0;i<(int)G[u].size();i++)    {        int v = G[u][i];        int w = W[u][i];        if(v==f) continue;        dp[v]=dp[u]^w;        dfs(v,u);    }}void solve(){    read();    dp[1]=0;    dfs(1,0);    scanf("%d",&Q);    while(Q--)    {        ll ans=0;        scanf("%d",&s);        for(int i=1;i<=N;i++)        {            int S = s^dp[i];            ans+=num[S];        }        if(s==0) ans+=N;        printf("%lld\n",ans/2);    }}int main(){    int T;    scanf("%d",&T);    while(T--) solve();    return 0;}


原创粉丝点击