• 【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 }
  • 相关阅读:
    Android控件系列之RadioButton&RadioGroup
    清理android桌面
    GPRS无限流量卡
    Android权限大全1
    android权限大全
    猎豹免费WIFI怎么用
    100%参考点总结
    手机淘宝flexible布局探索及最终方案
    (持续更新中)移动端web开发兼容总结
    (持续更新)浏览器兼容性总结—之前端开发常用属性及api
  • 原文地址:https://www.cnblogs.com/KonjakJuruo/p/6051051.html
Copyright © 2020-2023  润新知