hdu2017沈阳网络赛补题(一)mustedge mustedge(数剖求lca+树状数组)

  正式准备非常に写题前,先立个flag,倒过来写hdu(笑~)先是最后一页的第一题(大笑~)mustedge mustedge(这题的求解受到https://post.icpc-camp.org/d/724-hdoj-6200-mustedge-mustedge-mustedge的启发)

以及可以看http://blog.csdn.net/luotuoqingshan/article/details/77981430的标准程序

  题面:

Give an connected undirected graph with n nodes and m edges, ( n,m105 ) which has no selfloops or multiple edges initially .
Now we have q operations ( q105 ):
  
1 u v : add an undirected edge from u to v ; (uv&&1u,vn)
2 u v : count the number of mustedges from u to v ; (1u,vn) .

mustedge : we define set Ei as a path from u to v which contain edges in this path, and |k1Ei| is the number of mustedges . |x| means size of set x , and E1,E2Ek means all the paths.
It's guaranteed that n,m,q106
Please note that maybe there are more than one edges between two nodes after we add edges. They are not the same, which means they can be in a set at the same time. Read the sample data for more information.

思维过程:关键字:联通无向简单图,加边,查询点u到点v的所有路径的必经边数;

简化题意:引理一:一条边如果作为某两个点的必经边,那么对于任意两个不同点如果改边在这两点间的某一路径上,那么该边也是这两个点的必经边;

       因为如果边不在两点的任意路径上,那么它并不会加入查询。所以我们可以将一个图上的边分为两类必经边(绝对)和不必经过的边(绝对);

       那么我们要做的就是对一个图G进行边的分类,然后统计随便某一路径上的必经边就行了;我们取名必经边叫白边,不必经边叫黑边;

解法:首先对于最简单的联通图——树,显然都是白边,所以我们只要统计u,v路径上有多少条边,这是标准的树状数组的问题了;

        如果不是树呢?假设有它的某一生成树,然后再每次补上一条边,发现有一个变化,即u,v两点加边后它们和它们的lca构成了一个三角形的环,其他边没有影响,环上的边都变为黑(注意加边都是黑边),并且每次加边可以看作独立。所以只要我们提前求出u,v两点的lca再根据维护节点到根的边数由下面的公式update(u,-1),update(v,-1),update(lca,1),update(lca,1)维护即可,计算则由sum(u)+sum(v)-sum(lca)得出;最好的求lca自然是数剖啦,即为分类;

代码:

数剖求lca:

int head[2*maxn],to[maxn],son[maxn],siz[maxn];
int f[maxn],dep[maxn],tid[maxn],ran[maxn];
int tep[maxn],nex[2*maxn],tim,edge;
int num[maxn],tidr[maxn],rt[2*maxn];
void Init(){
    memset(head, -1, sizeof(head));
    memset(son, -1, sizeof(son));
    tim=edge=0;
}
void dfs1(int u,int father,int d){
    dep[u]=d;f[u]=father;siz[u]=-1;
    for (int i=head[u]; ~i; i=nex[i]) {
        int v=to[u];
        if (v==father) {
            continue;
        }
        dfs1(v, u, d+1);
        siz[u]+=siz[v];
        if (son[u]==-1||siz[v]>siz[son[u]]) {
            son[u]=v;
        }
    }
    
}
void dfs2(int u,int tp){
    tep[u]=tp;tid[u]=++tim;ran[tim]=u;
    if (son[u]==-1) {
        return;
    }
    dfs2(son[u], tp);
    for (int i=head[u]; ~i; i=nex[i]) {
        if (to[i]==son[u]||fa[u]==to[i]) {
            continue;
        }
        dfs2(to[i], to[i]);
    }
    tidr[u]=tim;
}
int lca(int x,int y){
    while (tep[x]!=tep[y]) {
        if (dep[tep[x]]<dep[tep[y]]) {
            swap(x, y);
        }
        x=fa[tep[x]];
    }
    return x;
}

树状数组:

int cost[maxn];
int lowbit(int x){
    return x&-x;
}
void add(int x,int val){
    while (x<=tim) {
        cost[x]+=val;
        x+=lowbit(x);
    }
}
void update(int l,int r,int d){
    add(l, d);add(r+1, -d);
}
int sum(int x){
    int ans=0;
    while (x>0) {
        ans+=cost[x];
        x+=lowbit(x);
    }
    return ans;
}

好啦~~拜拜

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值