【bzoj3648】环套树+点分治+树状数组

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 }
原文地址:https://www.cnblogs.com/KonjakJuruo/p/6051051.html