Codeforces 161.D. Distance in Tree-树分治(点分治,不容斥版)-树上距离为K的点对数量-蜜汁TLE (VK Cup 2012 Round 1)
这道题就是求树上距离为K的点对数量。以前写过<=K的点对数量,直接<=K的数量 - <K的数量,讲道理应该也是可以的,但是一直TLE11和TLE17样例。。。
最后换了一种写法,直接求,没有中间-子树的过程,最后过了,有点迷。。。
不容斥版的快,就这样。
代码:
1 //树分治-点分治 2 #include<bits/stdc++.h> 3 using namespace std; 4 typedef long long ll; 5 //#pragma GCC optimize(2) 6 //#define FI(n) FastIO::read(n) 7 const int inf=1e9+7; 8 const int maxn=1e5+10; 9 const int maxm=500+10; 10 11 int head[maxn<<1],tot; 12 int root,allnode,n,m,k; 13 bool vis[maxn]; 14 int deep[maxn],dis[maxn],siz[maxn],maxv[maxn];//deep[0]子节点个数(路径长度),maxv为重心节点 15 int num[maxm],cnt[maxm]; 16 ll ans=0; 17 18 //namespace FastIO {//读入挂 19 // const int SIZE = 1 << 16; 20 // char buf[SIZE], obuf[SIZE], str[60]; 21 // int bi = SIZE, bn = SIZE, opt; 22 // int read(char *s) { 23 // while (bn) { 24 // for (; bi < bn && buf[bi] <= ' '; bi++); 25 // if (bi < bn) break; 26 // bn = fread(buf, 1, SIZE, stdin); 27 // bi = 0; 28 // } 29 // int sn = 0; 30 // while (bn) { 31 // for (; bi < bn && buf[bi] > ' '; bi++) s[sn++] = buf[bi]; 32 // if (bi < bn) break; 33 // bn = fread(buf, 1, SIZE, stdin); 34 // bi = 0; 35 // } 36 // s[sn] = 0; 37 // return sn; 38 // } 39 // bool read(int& x) { 40 // int n = read(str), bf; 41 // 42 // if (!n) return 0; 43 // int i = 0; if (str[i] == '-') bf = -1, i++; else bf = 1; 44 // for (x = 0; i < n; i++) x = x * 10 + str[i] - '0'; 45 // if (bf < 0) x = -x; 46 // return 1; 47 // } 48 //}; 49 50 inline int read() 51 { 52 int x=0;char ch=getchar(); 53 while(ch<'0'||ch>'9')ch=getchar(); 54 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 55 return x; 56 } 57 58 struct node{ 59 int to,next,val; 60 }edge[maxn<<1]; 61 62 void add(int u,int v,int w)//前向星存图 63 { 64 edge[tot].to=v; 65 edge[tot].next=head[u]; 66 edge[tot].val=w; 67 head[u]=tot++; 68 } 69 70 void init()//初始化 71 { 72 memset(head,-1,sizeof head); 73 memset(vis,0,sizeof vis); 74 tot=0; 75 } 76 77 void get_root(int u,int father)//重心 78 { 79 siz[u]=1;maxv[u]=0; 80 for(int i=head[u];~i;i=edge[i].next){ 81 int v=edge[i].to; 82 if(v==father||vis[v]) continue; 83 get_root(v,u);//递归得到子树大小 84 siz[u]+=siz[v]; 85 maxv[u]=max(maxv[u],siz[v]);//更新u节点的maxv 86 } 87 maxv[u]=max(maxv[u],allnode-siz[u]);//保存节点size 88 if(maxv[u]<maxv[root]) root=u;//更新当前子树的重心 89 } 90 91 void get_dis(int u,int father)//获取子树所有节点与根的距离 92 { 93 if(dis[u]>k) return ; 94 ans+=num[k-dis[u]]; 95 cnt[dis[u]]++;//计数 96 for(int i=head[u];~i;i=edge[i].next){ 97 int v=edge[i].to; 98 if(v==father||vis[v]) continue; 99 int w=edge[i].val; 100 dis[v]=dis[u]+w; 101 get_dis(v,u); 102 } 103 } 104 105 void cal(int u,int now) 106 { 107 for(int i=1;i<=k;i++){//初始化,清空 108 num[i]=0; 109 } 110 num[0]=1; 111 for(int i=head[u];~i;i=edge[i].next){ 112 int v=edge[i].to; 113 if(vis[v]) continue; 114 for(int j=0;j<=k;j++){//初始化 115 cnt[j]=0; 116 } 117 dis[v]=now; 118 get_dis(v,u);//跑路径 119 for(int j=0;j<=k;j++){ 120 num[j]+=cnt[j];//计数 121 } 122 } 123 } 124 125 void solve(int u)//分治处理 126 { 127 cal(u,1); 128 vis[u]=1; 129 for(int i=head[u];~i;i=edge[i].next){ 130 int v=edge[i].to; 131 int w=edge[i].val; 132 if(vis[v]) continue; 133 allnode=siz[v]; 134 root=0; 135 get_root(v,u); 136 solve(root); 137 } 138 } 139 140 int main() 141 { 142 // FI(n);FI(k); 143 n=read();k=read(); 144 init(); 145 for(int i=1;i<n;i++){ 146 int u,v,w;w=1; 147 // FI(u);FI(v); 148 u=read();v=read(); 149 add(u,v,w); 150 add(v,u,w); 151 } 152 root=0;allnode=n;maxv[0]=inf; 153 get_root(1,0); 154 solve(root); 155 printf("%lld\n",ans); 156 return 0; 157 }