码迷,mamicode.com
首页 > 其他好文 > 详细

文章标题

时间:2015-07-22 16:09:17      阅读:122      评论:0      收藏:0      [点我收藏+]

标签:多校   最近公共祖先   二分法求公共祖先   

技术分享
比赛的时候以为这是一道动态维护树的中心,看了题解发现自己想错了,公共祖先的题目确实是少
这次学习了一下set
发现有很多使用简便的地方

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <vector>
#include <set>
#include <utility>
using namespace std;
#define N 111111
#define iter set<int>::iterator
int par[N][20];
int depth[N];
int dis[N];
int n,m;
int p[N];
int vis[N];
int cnt;
int dfn[N];
vector<pair<int,int>>edge[N];

set<int> ans;

void dfs(int u,int fa){
     dfn[++cnt]=u;
     p[u]=cnt;
     //printf("%d %d\n",u,fa);
     for(int i=1;i<18;i++){ //寻找他的十八辈祖宗
        par[u][i]=par[par[u][i-1]][i-1];
     }

     for(int i=0;i<edge[u].size();i++){
        int v=edge[u][i].first;
        if(fa==v) continue ;
        depth[v] = depth[u] + 1;
        dis[v] = dis[u] + edge[u][i].second;
        par[v][0] = u;
        dfs(v,u);
     }
}

int lca(int u,int v){
    if(depth[u]>depth[v]) swap(u,v);
    for(int k=0;k<18;k++){
        if((depth[v]-depth[u])>>k&1){
            v = par[v][k];
        }
    }
    if(v==u) return u;
    for(int k=17;k>=0;k--){
        if(par[u][k]!=par[v][k]){
            u=par[u][k];
            v=par[v][k];
        }
    }
    return par[u][0];
}

int tot;

int add(int u){
    if (ans.empty())
        return 0;
    int x, y;
    //寻找与u相邻的dfs序点
    iter it = ans.lower_bound(p[u]);
    iter itx = it;
    itx--;

    if (it == ans.end() || it == ans.begin()) {
        it = ans.begin();
        itx = ans.end();
        itx--;
    }
    y = (*it);
    x = (*itx);
    y = dfn[y];
    x = dfn[x];
    return dis[u] - dis[lca(x, u)] - dis[lca(y, u)] + dis[lca(x, y)];
}

void init(){
    for(int i=1;i<=n;i++){
        edge[i].clear();
    }
    memset(vis,0,sizeof(vis));
    memset(dfn,0,sizeof(dfn));
    memset(p,0,sizeof(p));
    memset(par,0,sizeof(par));
    memset(dis,0,sizeof(dis));
    memset(depth,0,sizeof(depth));
    cnt=0;
    ans.clear();
}

int main(){
    int T;
    int cas = 0;
    scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        init();
        int x,y,z;
        for(int i=1;i<n;i++){
            scanf("%d%d%d",&x,&y,&z);
            edge[x].push_back(make_pair(y,z));
            edge[y].push_back(make_pair(x,z));
        }
        /*
        for(int i=1;i<=n;i++){
                printf("%d :",i);
                for(int j=0;j<edge[i].size();j++){
                        printf("%d ",edge[i][j].first);
                }
                puts("");
        }
        */
        dis[1]=0;
        depth[1]=1;
        dfs(1,-1);
        /*
        for(int i=1;i<=n;i++){
                printf("%d %d %d\n",i,dis[i],par[i][0]);
        }
        */
        int sum=0;
        printf("Case #%d:\n",++cas);
        for(int i=1;i<=m;i++){
            scanf("%d%d",&x,&y);
            int tmp;

            if(x==1){
                if(!vis[y]){
                    vis[y]=1;
                    if (ans.size() == 0) {
                        ans.insert(p[y]);
                    } else {
                        tmp = add(y);
                        ans.insert(p[y]);
                        sum += tmp;
                    }
                }
            }
            else{
                if(vis[y]){
                    vis[y] = 0;
                    ans.erase(p[y]);
                    if (!ans.empty()) {
                        sum -= add(y);
                    }
                }
            }
            printf("%d\n",sum);
        }
    }
}

版权声明:都是兄弟,请随意转载,请注明兄弟是谁

文章标题

标签:多校   最近公共祖先   二分法求公共祖先   

原文地址:http://blog.csdn.net/u013076044/article/details/47004313

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!