「NOIP模拟赛」宠物之战
「问题描述」
众所周知,moreD的宠物已经被moreD奴役得体无完肤。这只宠物实在忍无可忍,把自己每天走魔法树的经历告诉了自己的宠物。同时他还说明了自己爬树是多么地慢,以至于moreD每天都残酷地训练他爬树。
幸运的是moreD的宠物的宠物不是moreD的宠物,moreD的宠物深知”宠物是用来宠的而不是用来奴役的”这一点,所以moreD的宠物 对待自己的宠物很有爱。所以moreD的宠物与其宠物商量着要推翻moreD的暴政,方法是把moreD告上法庭,就以自己每天被迫爬树来做证据。
由于魔法树是树,训练树当然也是树啦。
moreD的训练有着GX的文化,每天moreD会把自己的宠物通灵到树的一个端点上,这个通灵点可能与之前的通灵点相同。然后moreD命令他的宠物从这个点开始走,让这只宠物随便访问自己该天之前没有访问过的节点,一直走到该天无路可走,训练才会结束,宠物才可以休息。
moreD的宠物每天都会在这棵树上训练,幸运的是他每天走过的训练路径都不同,直到若干天后,所有可能的训练路径都被走遍了。
你,作为moreD宠物的宠物,一只被moreD的宠物宠着的宠物,当然想帮moreD的宠物算出他总共走过的路径长度啦。
「输入格式」
第一行包含两个正整数N,M,表示树的点数与边数。
接下来M行,每行三个正整数表示Li,bi,ci分别表示树上有一条长度为Li的连接bi,ci两个结点的边。
「输出格式」
仅一行表示答案。
「输入样例」
5 4
1 2 1
1 3 1
2 4 2
2 5 2
「输出样例」
37
「数据范围」
对于30%的数据N≤300
对于70%的数据N≤3,000
对于100%的数据对于所有输入的整数均不大于100,000,输入的树保证连通,无重边,无自环。
「样例解释」
可能的训练路径有(1-2-4),(1-2-5),(1-3),(2-4),(2-5),(2-1-3),(3-1-2-4),(3-1-2-5)
(4-2-5),(4-2-1-3),(5-2-4),(5-2-1-3)
长度依次为3,3,1,2,2,2,4,4,4,4,4,4。和为37.
题解
可以处理以i为根,子树大小,子树中的叶节点个数
i开始延伸到子树的底的边的边权和f1,其它边的边权和f2
然后分类统计答案
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 |
#include<iostream> #include<cstring> #include<cstdio> #include<cstdlib> #include<cmath> #include<algorithm> #include<set> #define ll long long #define inf 100000000 using namespace std; int read() { int x=0,f=1;char ch=getchar(); while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} return x*f; } ll ans,f1[100005],f2[100005],size[100005],bot[100005]; int last[100005],mark[100005]; int n,m,cnt; struct data{int to,next,v;}e[200005]; void insert(int u,int v,int w) { e[++cnt].to=v;e[cnt].next=last[u];last[u]=cnt;e[cnt].v=w; mark[v]++; } void dp(int x,int fa) { if(mark[x])bot[x]=1; for(int i=last[x];i;i=e[i].next) if(e[i].to!=fa) { dp(e[i].to,x); ans+=(bot[x]*size[e[i].to]+size[x]*bot[e[i].to])*e[i].v; ans+=f1[x]*(size[e[i].to]+bot[e[i].to]); ans+=f1[e[i].to]*(size[x]+bot[x]); ans+=f2[x]*bot[e[i].to]; ans+=f2[e[i].to]*bot[x]; bot[x]+=bot[e[i].to]; size[x]+=size[e[i].to]; f1[x]+=f1[e[i].to]+bot[e[i].to]*e[i].v; f2[x]+=f2[e[i].to]+(size[e[i].to]-bot[e[i].to])*e[i].v; } size[x]++; ans+=f1[x]; } int main() { n=read();m=read(); for(int i=1;i<=m;i++) { int w=read(),u=read(),v=read(); insert(u,v,w); insert(v,u,w); } for(int i=1;i<=n;i++) if(mark[i]!=1)mark[i]=0; for(int i=1;i<=n;i++) if(!mark[i]) { dp(i,0); break; } printf("%lld",ans); return 0; } |