zoukankan      html  css  js  c++  java
  • [cf1486F]Pairs of Paths

    以1为根建树,先将所有路径挂在lca上,再分两类讨论:

    1.lca相同,此时我们仅关心于lca上不经过第$a$和$b$个儿子路径数,容斥一下,即所有路径-经过$a$的-经过$b$的+经过$a$和$b$的,前三个很容易统计,最后一个用map即可

    (这样分类主要是避免lca相同时重复计数)

    2.lca不同,考虑其中lca深度较小的路径,将这条路径分为不包含lca的两段,那么另外一条路径的lca一定恰好在其中一条路径上

    更具体的,由于两段对称,仅考虑其中一段,如果暴力统计,也就是枚举这段上的每一个节点,假设先枚举的路径是第$a$个儿子,也就是求该点上所有路径-经过$a$的路径

    (特别的,对于叶子要将所有以该点为lca的路径全部累计)

    不难发现这件事情可以差分,即对于每一个点,记录”其到根路径通过上述方法得出的答案“,转移通过父亲求出,之后差分即可

    由于求lca还需要倍增,然后还有map,总复杂度为$o(nlog n)$

      1 #include<bits/stdc++.h>
      2 using namespace std;
      3 #define N 300005
      4 #define mp make_pair
      5 struct Edge{
      6     int nex,to;
      7 }edge[N<<1];
      8 struct path{
      9     int x,y,x0,y0;
     10 }a[N];
     11 vector<int>v[N];
     12 map<int,int>mat[N];
     13 int E,n,m,x,y,head[N],dep[N],id[N],sum[N],dp[N],f[N][21];
     14 long long ans;
     15 void add(int x,int y){
     16     edge[E].nex=head[x];
     17     edge[E].to=y;
     18     head[x]=E++;
     19 }
     20 int lca(int x,int y){
     21     if (dep[x]<dep[y])swap(x,y);
     22     for(int i=20;i>=0;i--)
     23         if (dep[f[x][i]]>=dep[y])x=f[x][i];
     24     if (x==y)return x;
     25     for(int i=20;i>=0;i--)
     26         if (f[x][i]!=f[y][i]){
     27             x=f[x][i];
     28             y=f[y][i];
     29         }
     30     return f[x][0];
     31 }
     32 int get(int x,int y){
     33     if (x==y)return x;
     34     for(int i=20;i>=0;i--)
     35         if (dep[f[x][i]]>dep[y])x=f[x][i];
     36     return x;
     37 }
     38 void dfs(int k,int fa,int s){
     39     dep[k]=s;
     40     f[k][0]=fa;
     41     for(int i=1;i<=20;i++)f[k][i]=f[f[k][i-1]][i-1];
     42     for(int i=head[k];i!=-1;i=edge[i].nex)
     43         if (edge[i].to!=fa)dfs(edge[i].to,k,s+1);
     44 }
     45 void calc(int k,int fa){
     46     id[0]=id[k]=0;
     47     for(int i=head[k];i!=-1;i=edge[i].nex)
     48         if (edge[i].to!=fa)id[edge[i].to]=++id[0];
     49     for(int i=0;i<v[k].size();i++)
     50         if (id[a[v[k][i]].x0]>id[a[v[k][i]].y0]){
     51             swap(a[v[k][i]].x,a[v[k][i]].y);
     52             swap(a[v[k][i]].x0,a[v[k][i]].y0);
     53         }
     54     for(int i=0;i<=id[0];i++){
     55         sum[i]=0;
     56         mat[i].clear();
     57     }
     58     for(int i=0;i<v[k].size();i++){
     59         sum[id[a[v[k][i]].x0]]++;
     60         sum[id[a[v[k][i]].y0]]++;
     61         mat[id[a[v[k][i]].x0]][id[a[v[k][i]].y0]]++;
     62     }
     63     for(int i=0;i<v[k].size();i++)
     64         if (!id[a[v[k][i]].x0]){
     65             if (!id[a[v[k][i]].y0])ans+=(int)v[k].size()-1;
     66             else ans+=(int)v[k].size()-sum[id[a[v[k][i]].y0]];
     67         }
     68         else{
     69             ans+=(int)v[k].size()-sum[id[a[v[k][i]].x0]]-sum[id[a[v[k][i]].y0]];
     70             ans+=mat[id[a[v[k][i]].x0]][id[a[v[k][i]].y0]];
     71         }
     72     for(int i=head[k];i!=-1;i=edge[i].nex)
     73         if (edge[i].to!=fa)dp[edge[i].to]=dp[k]+(int)v[k].size()-sum[id[edge[i].to]];
     74     for(int i=head[k];i!=-1;i=edge[i].nex)
     75         if (edge[i].to!=fa)calc(edge[i].to,k);
     76 }
     77 int main(){
     78     scanf("%d",&n);
     79     memset(head,-1,sizeof(head));
     80     for(int i=1;i<n;i++){
     81         scanf("%d%d",&x,&y);
     82         add(x,y);
     83         add(y,x);
     84     }
     85     dfs(1,1,0);
     86     scanf("%d",&m);
     87     for(int i=1;i<=m;i++){
     88         scanf("%d%d",&a[i].x,&a[i].y);
     89         int z=lca(a[i].x,a[i].y);
     90         a[i].x0=get(a[i].x,z);
     91         a[i].y0=get(a[i].y,z);
     92         v[z].push_back(i);
     93     }
     94     calc(1,0);
     95     ans/=2;
     96     for(int i=1;i<=m;i++){
     97         int z=lca(a[i].x,a[i].y);
     98         if (a[i].x!=z)ans+=dp[a[i].x]-dp[a[i].x0]+(int)v[a[i].x].size();
     99         if (a[i].y!=z)ans+=dp[a[i].y]-dp[a[i].y0]+(int)v[a[i].y].size();
    100     }
    101     printf("%lld",ans);
    102 }
    View Code
  • 相关阅读:
    三、thinkphp
    二、thinkphp
    一、thinkphp
    层次数据结构字符串处理,split函数使用
    jquery div层级选择器
    css ul li 制作导航条
    个人Android作品开发——FinancePad记账通
    springMVC+ibatis数据持久化入门级学习例子
    java reflect 例子
    java给图片加水印代码
  • 原文地址:https://www.cnblogs.com/PYWBKTDA/p/14428825.html
Copyright © 2011-2022 走看看