hihocoder 1167 LCA+树上前缀和

  题目大意:给出一棵树和树上的一些路径求些路径有多少对是相交的

  想一下就可以发现,每两条相交路径的交点中肯定有一个点是其中一条路径的两个端点的LCA

  然后求出

  1、每个点有多少条路径经过

  2、每个点是几条路径的LCA

  最后算一下就有ans,具体算法就不赘述

  1、用树上前缀和计算

  {

    

    树上前缀和:

    首先前提是已经理解 线性数组前缀和

      假设我们需要对a[]数组的[x,y]区间都加上w

      可以这样  a[x]+=w  a[y+1] -= w;  这里是y+1而不是y

      然后遍历a数组,a[i]+=a[i-1]。

      这样就得到a[]数组

    转换到树上的话,设一条路径的两端点为x,y  他们的LCA为z,那么可以把这条路径拆为 x到z  和y到z

    我们可以a[x]+=k  a[y]+=k a[fa[z]]-=k 然后因为两条路径对z点加了两次所以需要 a[z]-=k;

    最后从儿子节点一直加到根节点就可以得到每个节点有多少条路径经过

  }

  2、LCA

  {

     学了LCA就没什么问题了Trajan和在线都可以

  }

  刚学LCA ,代码写的很丑。。。= =!

    

    

 1 #include <cstdio>
 2 #include <cstring>
 3 #include <vector>
 4 #include <algorithm>
 5 #include <iostream>
 6 using namespace std;
 7 const int maxn = 100005;
 8 typedef long long LL;
 9 vector<int>f[maxn],son[maxn],q[maxn];
10 int vis[maxn],fat[maxn],anc[maxn];
11 int cnt[maxn],sum[maxn],fa[maxn];
12 int findd(int x)
13 {
14     int ret = x;
15     while(ret!=fat[ret])ret = fat[ret];
16     while(x!=ret)
17     {
18         int t = fat[x];
19         fat[x] = ret;
20         x = t;
21     }
22     return ret;
23 }
24 void dfs(int rt)
25 {
26     vis[rt] = 1;
27     int len = f[rt].size();
28     for(int i = 0;i<len;++i)
29     {
30         int u = f[rt][i];
31         if(vis[u])continue;
32         son[rt].push_back(u);
33         dfs(u);fa[u] = rt;
34     }
35 }
36 void lca(int rt)
37 {
38     for(int i = 0;i<son[rt].size();++i)
39     {
40         int u = son[rt][i];
41         lca(u);
42         fat[u] = rt;
43     }
44     vis[rt] = 1;
45     for(int i = 0;i<q[rt].size();++i)if(vis[q[rt][i]])
46     {
47         int z = anc[findd(q[rt][i])];
48         cnt[z]++;
49         sum[rt]++;
50         sum[q[rt][i]]++;
51         sum[z]--;
52         if(z!=1)sum[fa[z]]--;
53     }
54 }
55 void dfss(int rt)
56 {
57     int len = son[rt].size();
58     for(int i = 0;i<len;++i)
59     {
60         int u = son[rt][i];
61         dfss(u);
62         sum[rt]+=sum[u];
63     }
64 }
65 int main()
66 {
67 //    freopen("in.txt","r",stdin);
68     int n,m;cin>>n>>m;
69     memset(f,0,sizeof(f));
70     memset(q,0,sizeof(q));
71     memset(son,0,sizeof(son));
72     memset(vis,0,sizeof(vis));
73     memset(sum,0,sizeof(sum));
74     memset(cnt,0,sizeof(cnt));
75     for(int i = 1;i<=n;++i)
76         fat[i] = i,anc[i] = i;
77     for(int i = 1;i<n;++i)
78     {
79         int x,y;scanf("%d%d",&x,&y);
80         f[x].push_back(y);
81         f[y].push_back(x);
82     }
83     fa[1] = 1;
84     dfs(1);
85     memset(vis,0,sizeof(vis));
86     for(int i = 1;i<=m;++i)
87     {
88         int x,y;scanf("%d%d",&x,&y);
89         q[x].push_back(y);
90         q[y].push_back(x);
91     }
92     lca(1);
93     dfss(1);
94     LL ans = 0;
95     for(int i = 1;i<=n;++i)
96         ans+=1LL*(sum[i]-cnt[i])*cnt[i]+1LL*(cnt[i]-1)*cnt[i]/2;
97     cout<<ans<<endl;
98     return 0;
99 }

 

  

posted on 2015-05-06 23:44  round_0  阅读(415)  评论(0编辑  收藏  举报

导航