1. 程式人生 > >[POI2014]HOT-Hotels

[POI2014]HOT-Hotels

ret math names www || play 原理 但是 dcb

題目

因為三個點肯定會有一個中轉點,然後從中將一棵無根樹轉成有根數,然後再通過乘法原理(c2表示兩兩的乘積,若有第三個數就可以變成3數相乘,就可以乘法原理了)

為什麽要搜索每顆子樹而不從從自己的根開始搜了

以為這樣就有可能不是中轉點了

所以這樣的話時間復雜的為O(N^2),但是可以使用長鏈剖分優化為O(N),雖然我不知道怎麽用,沒有學過

技術分享圖片
#include<iostream>
#include<cstring>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace
std; inline long long read() { long long f=1,ans=0;char c; while(c<0||c>9){if(c==-)f=-1;c=getchar();} while(c>=0&&c<=9){ans=ans*10+c-0;c=getchar();} return f*ans; } long long c1[10001],c2[10001],n; struct node{ long long u,v,nex; }x[10001]; long long cnt=0; long
long ans[10001],head[5001],maxn,sum; void add(long long u,long long v) { x[cnt].u=u,x[cnt].v=v,x[cnt].nex=head[u],head[u]=cnt++; } void dfs(long long pos,long long fath,long long anss) { maxn=max(maxn,anss); ans[anss]++; for(long long i=head[pos];i!=-1;i=x[i].nex) { if(x[i].v!=fath) dfs(x[i].v,pos,anss+1
); } } int main() { memset(head,-1,sizeof(head)); n=read(); for(long long i=1;i<n;i++) { long long u=read(),v=read(); add(u,v),add(v,u); // cout<<i<<endl; } for(long long i=1;i<=n;i++) { memset(c1,0,sizeof(c1)); memset(c2,0,sizeof(c2)); for(long long j=head[i];j!=-1;j=x[j].nex) { maxn=0; dfs(x[j].v,i,1); for(long long k=1;k<=maxn;k++) { sum+=ans[k]*c2[k]; c2[k]+=c1[k]*ans[k]; c1[k]+=ans[k]; ans[k]=0; } } } cout<<sum; }
View Code

[POI2014]HOT-Hotels