hdu5296(倍增lca)

对于这道题,虽然题中有个求最小值,但它不是需要进行选择边的那种题,如果给定确定的点,把这些点连到一起,使得任意两点可达,那么只有一种方法(当然,去除掉多余的边,即叶子节点和根节点都必须在集合中)。所以可以每次加边时,只要找到一种方法,把它加入到已有树中就可以了,并且只有一种方法(当然,还是要去掉多余的边)。

至于根据dfs序找,假设要加入x这个点:

1)集合中有dfs序大于x的,并且也有小于x的,假设dfs序大于x的那个点是x的子节点,根据公式,可以的出,花费为0,余现实情况相符。

2)同1)中找出的两个点,只不过dfs序大于x的那个点不是x的子节点,那么此时必然离x最近的某个祖先节点虽然没在集合中,但是也己经在那个前几步生成的树当中,此时,只要把x到这个祖父节点的距离找出来,就是最小花费。根据公式所求,符合现实情况。

3)如果集合中不同时存在dfs序大于x的,和dfs序小于x的,假设,选出的此时集合中dfs序最大和最小的点,都是x的子节点,根据公式所求,符合现实要求。

4)选点同3,只是选出的两个点都是dfs序小于x的,那么如果此时这两个点的最近公共祖先是x的祖先节点,按照公式所求,符合现实要求,如果不是,按照公式所求,符合现实要求。

5)选点同3,只是选出的两个点都是dfs序大于x的,并且都不是x的子节点,同4

6)选点同3,只是选出的两个点都是dfs序大于x的,一个是x的子节点,一个不是x的子节点,按照公式所求,符合现实要求。


至于那道题,怎么正着推出这道题的解,现在只能把它当做一个结论来记了。


假设节点要连接到一个链中,链的定点(x,y),那么u连接到x的距离是dfn[u] + dfn[x] - 2dfn[ lca(u,x) ] ;

u连接到y的距离dfn[u] + dfn[y] - 2dfn[ lca(u,x) ] :

x连接到y的距离dfn[x] + dfn[y] - 2dfn[ lca(x,y) ] :

u连接到x-y这个链的距离 = (u到y+u到x-x到y)/2


迭代器讲解链接:http://www.cnblogs.com/yc_sunniwell/archive/2010/06/25/1764934.html

代码参考链接:http://www.bubuko.com/infodetail-988787.html

set的链接:http://baike.baidu.com/link?url=Uxof9XTaQURDJ9H8vSaVz4Cs8SOqee2kHyj37CBr2GrLzj-IqYGI5PGyBonm5C_oRWeBBbBbzfGDdlByuw1owK

用的是倍增lca。

(听说今天学校其余食堂就开门了,一共7个食堂,假期就开了4个,但是关的那三个中偏偏又两个常去的,开的这4个中虽然有两个个平常会去的,但是其中有一个,经常吃的窗口关了,所以这个暑假的食堂好凄惨!大哭

2015.8.31:

这道题也是刚做不久,回忆了一下过程,还沥沥在目!敲打

#include<stdio.h>
#include<string.h>
#include<iostream>
#include<set>
using namespace std;
#define N 100010
#define M 20

int deep[N],dis[N];
int vis[N];
int head[N],to[2*N],nextedge[2*N],wedge[2*N];
int dfsxv[N],dfsxf[N];
int fadp[N][M];
set<int> s;
set<int>::iterator iter;
int cou;
int time;

void add(int a,int b,int c){
    to[cou]=b;nextedge[cou]=head[a];wedge[cou]=c;head[a]=cou++;
}

void dfs(int u,int fa){
    dfsxv[u]=++time;
    dfsxf[time]=u;

    for(int i=head[u];i!=-1;i=nextedge[i]){
        int v=to[i];

        if(v==fa){
            continue;
        }
        else{
            deep[v]=deep[u]+1;
            dis[v]=dis[u]+wedge[i];
            fadp[v][0]=u;
            for(int j=1;(1<<j)<deep[v];j++){
                fadp[v][j]=fadp[fadp[v][j-1]][j-1];
            }
            dfs(v,u);
        }
    }

    return;
}

int lca(int a,int b){
    if(deep[a]<deep[b]){
        swap(a,b);
    }

    int tempi;
    for(tempi=0;(1<<tempi)<deep[a];tempi++);
    tempi--;
    for(int i=tempi;i>=0;i--){//使得合理答案永远在(a,a+2*tempi-1)的范围内
        if(deep[fadp[a][i]]>=deep[b]){
            a=fadp[a][i];
        }
    }

    if(a==b){
        return a;
    }
    for(tempi=0;(1<<tempi)<deep[a];tempi++);
    tempi--;
    for(int i=tempi;i>=0;i--){//是的合理答案,一直在(a+1,a+2*tempi)的范围内
        if(fadp[a][i]!=fadp[b][i]){
            a=fadp[a][i];
            b=fadp[b][i];
        }
    }

    return fadp[a][0];//尝试:在上面的循环中去掉i=0.->不能去掉i=0
}

int solve(int u){
    if(s.size()==0){
        return 0;
    }
    else{
        int x,y;
        iter=s.lower_bound(dfsxv[u]);
        if(iter==s.end()||iter==s.begin()){
            x=dfsxf[*s.begin()];//注意*
            y=dfsxf[*s.rbegin()];
        }
        else{
            x=dfsxf[*iter];
            iter--;
            y=dfsxf[*iter];
        }
        return dis[u]+dis[lca(x,y)]-dis[lca(u,x)]-dis[lca(u,y)];
    }
}

int main(){
    int t;
    int n,q;
    int a,b,c;

    scanf("%d",&t);
    for(int cas=1;cas<=t;cas++){
        scanf("%d%d",&n,&q);

        memset(head,-1,sizeof(head));
        cou=0;
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }

        memset(fadp,0,sizeof(fadp));//要是0,而不是1
        deep[0]=-1;
        deep[1]=1;
        dis[1]=0;
        time=0;
        dfs(1,-1);

        memset(vis,0,sizeof(vis));
        s.clear();//如果用容器什么的,也要考虑清理
        int ans=0;
        printf("Case #%d:\n",cas);
        for(int i=0;i<q;i++){
            scanf("%d%d",&a,&b);
            if(a==1){
                if(!vis[b]){
                    vis[b]=1;
                    ans+=solve(b);
                    s.insert(dfsxv[b]);
                }
            }
            else if(a==2){
                if(vis[b]){
                    vis[b]=0;
                    s.erase(dfsxv[b]);
                    ans-=solve(b);
                }
            }

            printf("%d\n",ans);
        }
    }

    return 0;
}



posted @ 2015-08-27 15:27  buzhidaohahaha  阅读(625)  评论(0)    收藏  举报