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

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 100010
struct 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;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章