hihocoder1167 Advanced Theoretical Computer Science[树剖][LCA]

来源:互联网 发布:雇一次网络水军多钱 编辑:程序博客网 时间:2024/06/11 03:35

Advanced Theoretical Computer Science
Time Limit: 20000MS Memory Limit: 262144KB 64bit IO Format: %lld & %llu
Submit

Status

Description
Yuuka is learning advanced theoretical computer science these days.But she cannot understand it. So she decided to hang out to relax.
Outside the door there is a tree of n nodes. She found there are P fairies on the tree. The fairies are very nervous, so each fairy only shows on a particular route on the tree. To be more specific, the i-th fairy will show on the path between nodes ai and bi.
Two fairies are friends if there route have some (no less than one) points in common.
Yuuka wants to know that how many pairs of fairies a,b (a!=b) are friends. Note that a,b and b,a are considered to be the same.

Input
The first line with two integers n and P (1 <= n, P <= 100000), meaning the size of the tree and the number of fairies. The nodes in the tree are numbered from 1 to n.
Then following n-1 lines with two integers a and b on each line, meaning there is an edge between a and b (a!=b).
Then following P lines, each line with two integers ai and bi, meaning the i-th fairy will show on the path from ai to bi. (ai!=bi)

Output
One line with an integer representing the answer.

Sample Input
6 3
1 2
2 3
2 4
4 5
4 6
1 3
1 5
5 6
Sample Output
2
Source
hihoCoder Challenge 11

Problem descriptions:
System Crawler 2016-10-18
Initialization.
Discuss

题意:给定树和链,求有多少对链有交点;
分析:可以分析得,两条链相交当且仅当LCA较深的链的LCA在另一条链上时,所以很容易想到用树剖搞定,可以对LCA的深度进行排序,然后询问一次改一个点,询问的是链上的点数,改变的是线段树上链上的点数(改链容易出问题);
第一次写和std对拍了很久都没有找出问题,但WA了,应该是某些特殊数据,复习的时候再写一次。
WA了的,球大神查错:

#include<iostream>#include<cstdio>#include<cmath>#include<algorithm>#include<cstring>using namespace std;const int maxn=1e5+5;int n,m,sta,fin,idx,cnt;int tov[maxn*2],fr[maxn],des[maxn*2],fa[maxn],dep[maxn],siz[maxn],sig[maxn];int tiilca[maxn*2],f[maxn*4][20],top[maxn],tii[maxn],son[maxn];struct node{    int lef,rig,sig; }a[maxn*8];struct node2{    int sta,fin,lca;}b[maxn];bool cmp(node2 x,node2 y){    return dep[x.lca]>dep[y.lca];}void addedge(int cur){    scanf("%d %d",&sta,&fin);    tov[2*cur-1]=fr[sta];fr[sta]=2*cur-1;des[2*cur-1]=fin;    tov[2*cur]=fr[fin];fr[fin]=2*cur;des[2*cur]=sta;}void dfs(int u,int fro,int ste){    fa[u]=fro;dep[u]=ste;siz[u]=1;    tiilca[++idx]=u;sig[u]=idx;f[idx][0]=idx;    for(int i=fr[u];i;i=tov[i])        if(des[i]!=fro){            dfs(des[i],u,ste+1);            tiilca[++idx]=u;            f[idx][0]=sig[u];            siz[u]+=siz[des[i]];            if(siz[des[i]]>siz[son[u]])                son[u]=des[i];        }}void dfs2(int u,int fro,int t){    top[u]=t;tii[u]=++cnt;    if(son[u])dfs2(son[u],u,t);    for(int i=fr[u];i;i=tov[i])        if(des[i]!=fro&&des[i]!=son[u])            dfs2(des[i],u,des[i]);}void bz(){    for(int i=1;i<=17;i++)for(int j=1;j<=2*n-1;j++)        f[j][i]=min(f[j][i-1],f[j+(1<<(i-1))][i-1]);}void build(int u,int lef,int rig){    a[u].lef=lef;a[u].rig=rig;    int mid=(lef+rig)>>1;    if(lef!=rig)        build(2*u,lef,mid),build(2*u+1,mid+1,rig);}int lookfor(int lef,int rig){    if(sig[lef]>sig[rig])swap(lef,rig);    int tmp=floor(log(sig[rig]-sig[lef]+1)/log(2));    return tiilca[min(f[sig[lef]][tmp],f[sig[rig]+1-(1<<tmp)][tmp])];}void update(int u,int dot){    a[u].sig++;    if(a[u].lef==a[u].rig&&a[u].rig==dot)return;    int mid=(a[u].lef+a[u].rig)>>1;    if(dot<=mid)update(2*u,dot);    else update(2*u+1,dot);}int query(int u,int lef,int rig){    if(a[u].lef==lef&&a[u].rig==rig)return a[u].sig;    else{        int mid=(a[u].lef+a[u].rig)>>1;        if(rig<=mid)return query(2*u,lef,rig);        else if(lef>mid)return query(2*u+1,lef,rig);        else return query(2*u,lef,mid)+query(2*u+1,mid+1,rig);    }}int queryctrl(int u){    sta=b[u].sta;fin=b[u].fin;    int ret=0;    int fa1=top[sta],fa2=top[fin];    while(fa1!=fa2){        if(dep[fa1]<dep[fa2]){            swap(sta,fin);swap(fa1,fa2);        }        ret+=query(1,tii[fa1],tii[sta]);        sta=fa[fa1];fa1=top[sta];    }    if(sta==fin)return ret;    if(tii[sta]>tii[fin])swap(sta,fin);    ret+=query(1,tii[sta],tii[fin]);    return ret;}void work(){    int ans=0;    for(int i=1;i<=m;i++)        scanf("%d %d",&b[i].sta,&b[i].fin);    for(int i=1;i<=m;i++)        b[i].lca=lookfor(b[i].sta,b[i].fin);    sort(b+1,b+m+1,cmp);    for(int i=1;i<=m;i++){    ans+=queryctrl(i);    update(1,tii[b[i].lca]);    }    printf("%d",ans);}void init(){    memset(f,127,sizeof(f));    scanf("%d %d",&n,&m);    for(int i=1;i<n;i++)addedge(i);    dfs(1,1,0);    dfs2(1,1,1);    bz();build(1,1,n);}int main(){    freopen("hihocoder1167.in","r",stdin);    freopen("hihocoder1167.out","w",stdout);    init();    work();    return 0;}

std:

#include <cstdio>#include <iostream>#include <cstring>using namespace std;typedef long long LL;#define MAXN 100010struct Edge {    int to, next;} edge[MAXN << 1];struct Node {    int to, next, num;} Query[MAXN << 1];struct node {    int u, v, lca;} input[MAXN];int totEdge, totQuery, n, m;int headEdge[MAXN], headQuery[MAXN];int ancestor[MAXN], father[MAXN], LCAnum[MAXN], sum[MAXN];bool vis[MAXN];void addEdge(int from, int to) {    edge[totEdge].to = to;    edge[totEdge].next = headEdge[from];    headEdge[from] = totEdge++;}void addQuery(int from, int to, int x) {    Query[totQuery].to = to;    Query[totQuery].num = x;    Query[totQuery].next = headQuery[from];    headQuery[from] = totQuery++;}void init() {    memset(headEdge, -1, sizeof(headEdge));    memset(headQuery, -1, sizeof(headQuery));    memset(father, -1, sizeof(father));    memset(vis, false, sizeof(vis));    memset(sum, 0, sizeof(sum));    memset(LCAnum, 0, sizeof(LCAnum));    totEdge = totQuery = 0;}int find_set(int x) {    if(x == father[x]) return x;    else return father[x] = find_set(father[x]);}void union_set(int x, int y) {    x = find_set(x); y = find_set(y);    if(x != y) father[y] = x;}void Tarjan(int u) {    father[u] = u;    for(int i = headEdge[u]; i != -1; i = edge[i].next) {        int v = edge[i].to;        if(father[v] != -1) continue;        Tarjan(v);        union_set(u, v);    }    for(int i = headQuery[u]; i != -1; i = Query[i].next) {        int v = Query[i].to;        if(father[v] == -1) continue;        input[Query[i].num].lca = find_set(v);    }}void DFS(int u, int pre) {    vis[u] = 1;    sum[u] = sum[pre] + LCAnum[u];    for(int i = headEdge[u]; i != -1; i = edge[i].next) {        int v = edge[i].to;        if(vis[v]) continue;        DFS(v, u);    }}int main() {    freopen("hihocoder1167.in","r",stdin);    freopen("hihocoder11671.out","w",stdout);    init();    scanf("%d%d", &n, &m);    for(int i = 0; i < n - 1; i++) {        int a, b;        scanf("%d%d", &a, &b);        addEdge(a, b); addEdge(b, a);    }    for(int i = 0; i < m; i++) {        int a, b;        scanf("%d%d", &a, &b);        input[i].u = a, input[i].v = b;        addQuery(a, b, i); addQuery(b, a, i);    }    Tarjan(1);    for(int i = 0; i < m; i++)        LCAnum[input[i].lca]++;    DFS(1, 0);    LL ans = 0;    for(int i = 0; i < m; i++) {        ans += (sum[input[i].u] + sum[input[i].v] - 2 * sum[input[i].lca]);    }    for(int i = 1; i <= n; i++) {        ans += (LL)LCAnum[i] * (LCAnum[i] - 1) / 2;    }    printf("%lld\n", ans);    return 0;}
0 0
原创粉丝点击