51nod1253 Kundu and Tree

树包含N个点和N-1条边。树的边有2中颜色红色(‘r‘)和黑色(‘b‘)。给出这N-1条边的颜色,求有多少节点的三元组(a,b,c)满足:节点a到节点b、节点b到节点c、节点c到节点a的路径上,每条路径都至少有一条边是红色的。

注意(a,b,c), (b,a,c)以及所有其他排列被认为是相同的三元组。输出结果对1000000007取余的结果。

Input

第1行:1个数N(1 <= N <= 50000)
第2 - N行:每行2个数加一个颜色,表示边的起始点和结束的以及颜色。

Output

输出1个数,对应符合条件的3元组的数量。

预处理对每条边(a,b),从a出发经过b的路径有多少条是经过/不经过红边的

存在两种情况:

1.a,b,c两两间路径不经过第三点,这时三条路径有唯一公共点,公共点到a,b,c的路径至少有两条有红边,由此可以统计

2.a,b,c中有两点的路径经过第三点,这时枚举被经过的点进行统计

#include<cstdio>
typedef long long i64;
const int N=50007,R=N*40;
char buf[R+7],*ptr=buf-1;
int _(){
    int x=0,c=*++ptr;
    while(c<48)c=*++ptr;
    while(c>47)x=x*10+c-48,c=*++ptr;
    return x;
}
int _c(){
    int c=*++ptr;
    while(c<‘a‘)c=*++ptr;
    return c==‘r‘;
}
int n;
int es[N*2],enx[N*2],e0[N],ev[N*2],ep=2;
int f1[N],f2[N],f3[N],sz[N];
i64 ans=0;
void dfs1(int w,int pa){
    sz[w]=1;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa){
            dfs1(u,w);
            sz[w]+=sz[u];
            if(ev[i])f1[w]+=f3[u]=sz[u];
            else f1[w]+=f3[u]=f1[u];
        }
    }
}
void dfs2(int w,int pa){
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa){
            if(ev[i])f2[u]=n-sz[u];
            else f2[u]=f2[w]+f1[w]-f1[u];
            dfs2(u,w);
        }
    }
}
void dfs3(int w,int pa){
    static i64 fs[N],fl[N],fr[N],ss[N],sl[N],sr[N];
    static int p;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        if(u!=pa)dfs3(u,w);
    }
    p=0;
    for(int i=e0[w];i;i=enx[i]){
        int u=es[i];
        ++p;
        if(u!=pa){
            fs[p]=fl[p]=fr[p]=f3[u];
            ss[p]=sl[p]=sr[p]=sz[u]-fs[p];
        }else{
            fs[p]=fl[p]=fr[p]=f2[w];
            ss[p]=sl[p]=sr[p]=n-sz[w]-fs[p];
        }
    }
    i64 a0=ans;
    for(int i=2;i<=p;++i)fl[i]+=fl[i-1],sl[i]+=sl[i-1];
    for(int i=p-1;i;--i)fr[i]+=fr[i+1],sr[i]+=sr[i+1];
    for(int i=2;i<p;++i){
        ans+=fl[i-1]*(fs[i]*sr[i+1]+ss[i]*fr[i+1]);
        ans+=(sl[i-1]+fl[i-1])*fs[i]*fr[i+1];
    }
    for(int i=1;i<p;++i)ans+=fl[i]*fs[i+1];
}
int main(){
    fread(buf,1,R,stdin);
    n=_();
    for(int i=1;i<n;++i){
        int a=_(),b=_(),c=_c();
        es[ep]=b;enx[ep]=e0[a];ev[ep]=c;e0[a]=ep++;
        es[ep]=a;enx[ep]=e0[b];ev[ep]=c;e0[b]=ep++;
    }
    dfs1(1,0);
    dfs2(1,0);
    dfs3(1,0);
    printf("%lld",ans%1000000007);
    return 0;
}
时间: 2024-10-19 02:01:53

51nod1253 Kundu and Tree的相关文章

51Nod1253 Kundu and Tree 容斥原理

原文链接https://www.cnblogs.com/zhouzhendong/p/51Nod1253.html 题目传送门 - 51Nod1253 题意 树包含 N 个点和 N-1 条边.树的边有 2 中颜色红色 ('r') 和黑色 ('b') .给出这 N-1 条边的颜色,求有多少节点的三元组 (a,b,c) 满足:节点 a 到节点 b .节点 b 到节点 c .节点 c 到节点 a 的路径上,每条路径都至少有一条边是红色的.注意 (a,b,c) , (b,a,c) 以及所有其他排列被认为

一些计数题

可能是血(水)考前最后一篇题解了,不过还是写写题解吧. 大部分来源51nod 51nod1253 Kundu and Tree 挺思博的一道题.首先黑色边没用,所以可以把其视为连通块,然后走出该连通块必然要经过至少一条红色边,于是就是总方案数减3个全在一个黑连通块再减去2个在一个黑连通块. #include<bits/stdc++.h> using namespace std; typedef long long ll; const int N=5e4+7,mod=1e9+7; int n,a

Hackerrank--Kundu and Tree

题目链接 Kundu is true tree lover. Tree is a connected graph having N vertices and N-1 edges. Today when he got a tree, he colored each edge with one of either red(r) or black(b) color. He is interested in knowing how many triplets(a,b,c) of vertices are

easyui js取消选中 Tree 指定节点

取消所有选中 var rootNodes = treeObject.tree('getRoots'); for ( var i = 0; i < rootNodes.length; i++) { var node = treeObject.tree('find', rootNodes[i].id); treeObject.tree('uncheck', node.target); }

Maximum Depth of Binary Tree

这道题为简单题 题目: Given a binary tree, find its maximum depth.The maximum depth is the number of nodes along the longest path from the root node down to the farthest leaf node. 思路: 我是用递归做的,当然也可以用深搜和广搜,递归的话就是比较左右子树的深度然后返回 代码: 1 # Definition for a binary tre

538. Convert BST to Greater Tree 二叉搜索树转换为更大树

Given a Binary Search Tree (BST), convert it to a Greater Tree such that every key of the original BST is changed to the original key plus sum of all keys greater than the original key in BST. Example: Input: The root of a Binary Search Tree like thi

SPOJ375 Query on a tree

https://vjudge.net/problem/SPOJ-QTREE 题意: 一棵树,每条边有个权值 两种操作 一个修改每条边权值 一个询问两点之间这一条链的最大边权 点数<=10000 多组测试数据,case<=20 Example Input: 1 3 1 2 1 2 3 2 QUERY 1 2 CHANGE 1 3 QUERY 1 2 DONE Output: 1 3 #include<cstdio> #include<iostream> #include&

POJ 1741 Tree(树的点分治,入门题)

Tree Time Limit: 1000MS   Memory Limit: 30000K Total Submissions: 21357   Accepted: 7006 Description Give a tree with n vertices,each edge has a length(positive integer less than 1001).Define dist(u,v)=The min distance between node u and v.Give an in

命令-tree

tree命令 tree - list contents of directories in a tree-like format. 显示目录的层级结构: tree 命令英文理解为树的意思,其功能是创建文件列表,将目录所有文件以树状的形式列出来.linux中的tree命令默认并不会安装,所以需要通过yum install tree -y来安装此命令. [SYNOPSIS] tree [options] [directory] [OPTIONS] -L level:指定要显示的层级: -d:仅列出目