tree 1s 128M by hzw
czy神犇种了一棵树,他想知道地球的质量
给定一棵n个点的树,求树上经过点的个数≥K的路径数量ans
对于部分数据,树上某两点间会多出最多一条无向边
输入数据
n,m,K
接下来n行,每行u,v表示u与v间有无向边连接
输出数据
ans
样例数据
input
5 5 2
1 3
2 4
3 5
4 1
5 2
output
20
数据范围
30%的数据n,m<=5000
100%的数据n,m<=100000
其中有50%的数据满足m+1=n,具体如下
测试点
前3个小数据1树2链 3环+外向树
后7个大数据4-6树 7-8环 9-10环+外向树
如果没有环,那就是经典点分治题目啦。
题目保证有且只有一个环,那么我们先随便拆掉环上的一条边,然后用点分治算出不经过这条边的满足题意的路径数量。
ans需要加上经过这条边的满足题意的路径数量。
这个怎么求呢?
看我丑丑的图。。
环可以用并查集判断(注意每次更新fa[x]不然容易暴栈),要删的边就直接不要插入。
树状数组用来判断>=x的有多少个,注意0会死循环,加个偏移量,负数就直接升到1。
代码:
1 #include<cstdio>
2 #include<cstdlib>
3 #include<cstring>
4 #include<iostream>
5 #include<algorithm>
6 using namespace std;
7
8 typedef long long LL;
9 const int N=100010;
10 int n,m,K,cx,cy,cl,tl,sl,len,has_circle;
11 int first[N],c[N],s[N],t[N],d[N],mark[N],size[N],f[N],cir[N];
12 struct node{
13 int x,y,next;
14 }a[2*N];
15 LL ans;
16
17 bool cmp(int x,int y){return x<y;}
18
19 void ins(int x,int y)
20 {
21 a[++len].x=x;a[len].y=y;
22 a[len].next=first[x];first[x]=len;
23 }
24
25 int findfa(int x)
26 {
27 if(f[x]==x) return x;
28 return f[x]=findfa(f[x]);
29 }
30
31 void add(int x,int val)
32 {
33 x++;
34 for(int i=x;i>=1;i-=(i&(-i))) c[i]+=val;
35 }
36 int getsum(int x)
37 {
38 x++;
39 if(x<=0) x=1;
40 int now=0;
41 for(int i=x;i<=n;i+=(i&(-i))) now+=c[i];
42 return now;
43 }
44
45 void find_root(int x,int fa,int tot,int &root)
46 {
47 size[x]=1;
48 bool bk=1;
49 for(int i=first[x];i;i=a[i].next)
50 {
51 int y=a[i].y;
52 if(y==fa || mark[y]) continue;
53 find_root(y,x,tot,root);
54 size[x]+=size[y];
55 if(2*size[y]>tot) bk=0;
56 }
57 if(bk && 2*(tot-size[x])<=tot) root=x;
58 }
59
60 void DFS(int x,int fa,int tmp)
61 {
62 if(tmp)
63 {
64 d[x]=d[fa]+1;
65 ans+=getsum(K-d[x]);
66 }
67 t[++tl]=d[x];
68 size[x]=1;
69 for(int i=first[x];i;i=a[i].next)
70 {
71 int y=a[i].y;
72 if(y==fa || mark[y]) continue;
73 DFS(y,x,tmp);
74 size[x]+=size[y];
75 }
76 }
77
78 void dfs(int x,int tot)
79 {
80 find_root(x,0,tot,x);
81 sl=0;s[++sl]=0;add(0,1);
82 mark[x]=1;d[x]=0;
83 for(int i=first[x];i;i=a[i].next)
84 {
85 int y=a[i].y;
86 if(mark[y]) continue;
87 tl=0;
88 DFS(y,x,1);
89 for(int j=1;j<=tl;j++)
90 {
91 s[++sl]=t[j];
92 add(t[j],1);
93 }
94 }
95 for(int i=1;i<=sl;i++) add(s[i],-1);
96 for(int i=first[x];i;i=a[i].next)
97 {
98 int y=a[i].y;
99 if(mark[y]) continue;
100 dfs(y,size[y]);
101 }
102 }
103
104 void find_circle(int x,int fa)
105 {
106 if(x==cy) {cir[++cl]=x;return ;}
107 for(int i=first[x];i;i=a[i].next)
108 {
109 int y=a[i].y;
110 if(y==fa) continue;
111 find_circle(y,x);
112 if(mark[y]) {cir[++cl]=x;mark[x]=1;}
113 }
114 }
115
116 void solve_circle()
117 {
118 memset(c,0,sizeof(c));
119 memset(mark,0,sizeof(mark));
120 mark[cx]=mark[cy]=1;
121 find_circle(cx,0);
122
123 // for(int i=1;i<=cl;i++) printf("%d ",cir[i]);printf("
");
124 memset(mark,0,sizeof(mark));
125 d[0]=-1;tl=0;
126 DFS(cy,0,1);
127 for(int i=1;i<=tl;i++) add(t[i],1);
128 for(int i=1;i<=cl;i++) mark[cir[i]]=1;
129
130 K--;
131 for(int i=cl;i>=1;i--)
132 {
133 tl=0;
134 mark[cir[i]]=0;
135 DFS(cir[i],0,0);
136 for(int j=1;j<=tl;j++) add(t[j],-1);
137 if(i<cl) d[cir[i]]=d[cir[i+1]]+1;
138 DFS(cir[i],cir[i+1],1);
139 mark[cir[i]]=1;
140 }
141 }
142
143 int main()
144 {
145 // freopen("a.in","r",stdin);
146 // freopen("a.out","w",stdout);
147 freopen("tree.in","r",stdin);
148 freopen("tree.out","w",stdout);
149 scanf("%d%d%d",&n,&m,&K);K--;
150 int x,y,xx,yy;
151 ans=0;len=0;has_circle=0;
152 memset(c,0,sizeof(c));
153 memset(mark,0,sizeof(mark));
154 memset(first,0,sizeof(first));
155 for(int i=1;i<=n;i++) f[i]=i;
156 for(int i=1;i<=m;i++)
157 {
158 scanf("%d%d",&x,&y);
159 xx=findfa(x);yy=findfa(y);
160 if(xx==yy)
161 {
162 has_circle=1;
163 cx=x;cy=y;
164 }
165 else
166 {
167 ins(x,y);ins(y,x);
168 f[xx]=yy;
169 }
170 }
171 // for(int i=1;i<=len;i+=2) printf("%d --> %d
",a[i].x,a[i].y);
172 dfs(1,n);
173 if(has_circle) solve_circle();
174 printf("%lld
",ans);
175 return 0;
176 }