HDU 5416 异或运算性质 思维

HDU 5416

题目链接:

http://acm.hdu.edu.cn/showproblem.php?pid=5416

题意:

给一棵树,每条边有权值。问f(u,v) = s(u,v)对数有多少对。u<=v

思路:

赛后过。

刚开始以为是什么不知道的算法,上网看标题是树形dp或者dfs。回来想了又想……不对啊,树形dp也不能dp 10^5 * 10^5。就算如此,怎么算两个叶子节点的路径……

题解给出这样的解释f(u,v) = f(1,u)^f(1,v)。秒懂。相同则去掉。

这说明异或运算是有性质的,异或运算是可以利用的!

源码:

#include <cstdio>

#include <cmath>

#include <cstring>

#include <algorithm>

#include <cstdlib>

#include <string>

#include <iostream>

using namespace std;

#define LL long long

const int MAXN = 400000;

int dp[MAXN];

int cnt, n;

int lv[MAXN];

int head[MAXN];

struct Edge

{

    int u, v, val, ne;

    Edge(){}

    Edge(int _u, int _v, int _val){u = _u, v = _v, val = _val, ne = head[u];}

}edge[MAXN*2];

//int vis[MAXN];

void addedge(int u, int v, int val)

{

    edge[cnt] = Edge(u, v, val);

    head[u] = cnt++;

    edge[cnt] = Edge(v, u, val);

    head[v] = cnt++;

}

void DFS(int u, int fa, int val)

{

    int now = head[u];

    lv[u] = val;

//    if(vis[u] == 0){

//        vis[u] = 1;

//        if(fa > 0)

//            dp[val]++;

//    }

    while(now != -1){

        int v = edge[now].v;

        if(v != fa){

            DFS(v, u, val ^ edge[now].val);

        }

        now = edge[now].ne;

    }

}

void init()

{

    memset(dp, 0, sizeof(dp));

    DFS(1, -1, 0);

}

int main()

{

//    freopen("1011.in", "r", stdin);

//    freopen("my data 1011.out", "w", stdout);

    int t;

    scanf("%d", &t);

    while(t--){

        scanf("%d", &n);

        int u, v, val;

        cnt = 0;

        memset(head, -1, sizeof(head));

        for(int i = 0 ; i < n - 1 ; i++){

            scanf("%d%d%d", &u, &v, &val);

            addedge(u, v, val);

        }

        memset(vis, 0, sizeof(vis));

        init();

        for(int i = 1 ; i <= n ; i++)

            dp[lv[i]]++;

        int q;

        scanf("%d", &q);

        for(int i = 0 ; i < q ; i++){

            int s;

            scanf("%d", &s);

            LL ans = 0;

            for(int i = 1 ; i <= n ; i++){

                LL temp = lv[i] ^ s;

                ans += dp[temp];

            }

            LL tans = 0;

            if(s == 0)

                tans = n ;

            printf("%I64d\n", (ans + tans) / 2);

        }

    }

    return 0;

}

再贴一个错误的版本

#include <cstdio>#include <cmath>#include <cstring>#include <algorithm>#include <cstdlib>#include <string>#include <iostream>using namespace std;#define LL long longconst int MAXN = 400000;int dp[MAXN];int cnt, n;int lv[MAXN];int head[MAXN];struct Edge{    int u, v, val, ne;    Edge(){}    Edge(int _u, int _v, int _val){u = _u, v = _v, val = _val, ne = head[u];}}edge[MAXN*2];int vis[MAXN];void addedge(int u, int v, int val){    edge[cnt] = Edge(u, v, val);    head[u] = cnt++;    edge[cnt] = Edge(v, u, val);    head[v] = cnt++;}void DFS(int u, int fa, int val){    int now = head[u];    lv[u] = val;    if(vis[u] == 0){        vis[u] = 1;        if(fa > 0)            dp[val]++;    }    while(now != -1){        int v = edge[now].v;        if(v != fa){            DFS(v, u, val ^ edge[now].val);        }        now = edge[now].ne;    }}void init(){    memset(dp, 0, sizeof(dp));    DFS(1, -1, 0);}int main(){//    freopen("1011.in", "r", stdin);//    freopen("my data 1011.out", "w", stdout);    int t;    scanf("%d", &t);    while(t--){        scanf("%d", &n);        int u, v, val;        cnt = 0;        memset(head, -1, sizeof(head));        for(int i = 0 ; i < n - 1 ; i++){            scanf("%d%d%d", &u, &v, &val);            addedge(u, v, val);        }        memset(vis, 0, sizeof(vis));        init();//        for(int i = 1 ; i <= n ; i++)//            dp[lv[i]]++;        int q;        scanf("%d", &q);        for(int i = 0 ; i < q ; i++){            int s;            scanf("%d", &s);            LL ans = 0;            for(int i = 1 ; i <= n ; i++){                LL temp = lv[i] ^ s;                ans += dp[temp];            }            LL tans = 0;            if(s == 0)                tans = n ;            printf("%I64d\n", (ans + tans) / 2);        }    }    return 0;}

以及改进后版本

#include <cstdio>

#include <cmath>

#include <cstring>

#include <algorithm>

#include <cstdlib>

#include <string>

#include <iostream>

using namespace std;

#define LL long long

const int MAXN = 400000;

int dp[MAXN];

int cnt, n;

int lv[MAXN];

int head[MAXN];

int mmax;

struct Edge

{

    int u, v, val, ne;

    Edge(){}

    Edge(int _u, int _v, int _val){u = _u, v = _v, val = _val, ne = head[u];}

}edge[MAXN*2];

int vis[MAXN];

void addedge(int u, int v, int val)

{

    edge[cnt] = Edge(u, v, val);

    head[u] = cnt++;

    edge[cnt] = Edge(v, u, val);

    head[v] = cnt++;

}

void DFS(int u, int fa, int val)

{

    int now = head[u];

    lv[u] = val;

    mmax = max(val, mmax);

    if(vis[u] == 0){

        vis[u] = 1;

//        if(fa > 0)

            dp[val]++;

    }

    while(now != -1){

        int v = edge[now].v;

        if(v != fa){

            DFS(v, u, val ^ edge[now].val);

        }

        now = edge[now].ne;

    }

}

void init()

{

    mmax = 0;

    memset(dp, 0, sizeof(dp));

    DFS(1, -1, 0);

}

int main()

{

//    freopen("1011.in", "r", stdin);

//    freopen("my data 1011 b.txt", "w", stdout);

    int t;

    scanf("%d", &t);

    while(t--){

        scanf("%d", &n);

        int u, v, val;

        cnt = 0;

        memset(head, -1, sizeof(head));

        for(int i = 0 ; i < n - 1 ; i++){

            scanf("%d%d%d", &u, &v, &val);

            addedge(u, v, val);

        }

        memset(vis, 0, sizeof(vis));

        init();

//        for(int i = 1 ; i <= n ; i++)

//            dp[lv[i]]++;

//        for(int i = 0 ; i <= mmax ; i++)

//            printf("%d ", dp[i]);

//        printf("dp\n");

        int q;

        scanf("%d", &q);

        for(int i = 0 ; i < q ; i++){

            int s;

            scanf("%d", &s);

            LL ans = 0;

            for(int i = 1 ; i <= n ; i++){

                LL temp = lv[i] ^ s;

                ans += dp[temp];

            }

            LL tans = 0;

            if(s == 0)

                tans = n ;

            printf("%I64d\n", (ans + tans) / 2);

        }

    }

    return 0;

}

/*

 

9

2 1 2

3 1 0

4 3 7

5 4 3

6 2 2

7 2 5

8 4 8

9 6 2

9

3

2

5

2

0

5

2

7

4

*/

 

主要是DFS中对于(1,1)点也要加上,最后若s == 0时再加上所有点个数n。若不是,则会(1,1)会少算一次,最后ans/2时会得到错误答案。 

你可能感兴趣的:(HDU 5416 异或运算性质 思维)