zoukankan      html  css  js  c++  java
  • HDU 5296 Annoying problem dfs序 lca

    Annoying problem

    题目连接:

    http://acm.hdu.edu.cn/showproblem.php?pid=5296

    Description

    Coco has a tree, whose nodes are conveniently labeled by 1,2,…,n, which has n-1 edge,each edge has a weight. An existing set S is initially empty.
    Now there are two kinds of operation:

    1 x: If the node x is not in the set S, add node x to the set S
    2 x: If the node x is in the set S,delete node x from the set S

    Now there is a annoying problem: In order to select a set of edges from tree after each operation which makes any two nodes in set S connected. What is the minimum of the sum of the selected edges’ weight ?

    Input

    one integer number T is described in the first line represents the group number of testcases.( T<=10 )
    For each test:
    The first line has 2 integer number n,q(0<n,q<=100000) describe the number of nodes and the number of operations.
    The following n-1 lines each line has 3 integer number u,v,w describe that between node u and node v has an edge weight w.(1<=u,v<=n,1<=w<=100)
    The following q lines each line has 2 integer number x,y describe one operation.(x=1 or 2,1<=y<=n)

    Output

    Each testcase outputs a line of "Case #x:" , x starts from 1.
    The next q line represents the answer to each operation.

    Sample Input

    1
    6 5
    1 2 2
    1 5 2
    5 6 2
    2 4 2
    2 3 2
    1 5
    1 3
    1 4
    1 2
    2 5

    Sample Output

    Case #1:
    0
    6
    8
    8
    4

    Hint

    题意

    给你一棵树,现在有两个操作

    1.把某个点染成黑色

    2.把某个点染成白色

    然后每次操作结束后,问你黑色点构成的树的所有边权和是多少。

    一开始全是白色的点。

    题解:

    首先黑色点构成的树一定是唯一的。

    然后我们加入一个点,就只用考虑以前那堆点中dfs序比他小和比他大的点u,v。

    如果找不到的话,找字典序最大和最小的点就好了。

    然后这棵树增加的距离就是dis(x,u)+dis(x,v)+dis(u,v)

    删除点也是一样的。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    
    const int maxn = 1e5+7;
    int flag[maxn],idx[maxn],cnt=1,n,q,LCA[maxn][21],deep[maxn],G[maxn][21];
    vector<pair<int,int> >E[maxn];
    set<pair<int,int> >S;
    long long ans = 0;
    void init()
    {
        ans = 0;
        S.clear();cnt=1;
        memset(idx,0,sizeof(idx));
        memset(flag,0,sizeof(flag));
        memset(LCA,0,sizeof(LCA));
        memset(G,0,sizeof(G));
        memset(deep,0,sizeof(deep));
        for(int i=0;i<maxn;i++)E[i].clear();
    }
    void dfs(int x,int fa)
    {
        idx[x]=cnt++;
        for(int i=0;i<E[x].size();i++)
        {
            int v = E[x][i].first;
            if(v==fa)continue;
            LCA[v][0]=x,deep[v]=deep[x]+1,G[v][0]=E[x][i].second;
            dfs(v,x);
        }
    }
    
    long long QueryDis(int u , int v){
        long long ans = 0;
    	if(deep[u] < deep[v]) swap( u , v );
    	for(int i = 20 ; i >= 0 ; -- i ) if( deep[u] - (1 << i) >= deep[v] ) ans += G[u][i],u = LCA[u][i];
    	if( u == v ) return ans;
        for(int i = 20 ; i >= 0 ; -- i ) if( LCA[u][i] != LCA[v][i] ) ans += (G[u][i] + G[v][i]) , u = LCA[u][i] , v = LCA[v][i];
        return ans + G[u][0] + G[v][0];
    }
    
    void Lca_init()
    {
        for(int j = 1 ; j <= 20 ; ++ j)
            for(int i = 1 ; i <= n ; ++ i)
                if(LCA[i][j-1]){
                    LCA[i][j]=LCA[LCA[i][j-1]][j-1];
                    G[i][j] = G[i][j-1] + G[LCA[i][j-1]][j-1];
                }
    }
    long long solve(int x)
    {
        if(S.size()==0)return 0;
        set<pair<int,int> >::iterator it;
        it=S.lower_bound(make_pair(idx[x],x));
        int d1,d2;
        if(it==S.begin()||it==S.end())
        {
            d1=S.begin()->second;
            d2=S.rbegin()->second;
        }
        else
        {
            d1=it->second;
            it--;
            d2=it->second;
        }
        return QueryDis(d1,x)+QueryDis(d2,x)-QueryDis(d1,d2);
    }
    void solve()
    {
        init();
        scanf("%d%d",&n,&q);
        for(int i=1;i<n;i++)
        {
            int x,y,z;scanf("%d%d%d",&x,&y,&z);
            E[x].push_back(make_pair(y,z));
            E[y].push_back(make_pair(x,z));
        }
        dfs(1,-1);
        Lca_init();
        while(q--)
        {
            int op,x;scanf("%d%d",&op,&x);
            if(op==1&&flag[x]==1);
            else if(op==2&&flag[x]==0);
            else if(op==1)flag[x]=1,ans+=solve(x),S.insert(make_pair(idx[x],x));
            else if(op==2)flag[x]=0,S.erase(make_pair(idx[x],x)),ans-=solve(x);
            printf("%lld
    ",ans/2);
        }
    }
    
    int main()
    {
        int t;scanf("%d",&t);
        for(int i=1;i<=t;i++)
        {
            printf("Case #%d:
    ",i);
            solve();
        }
        return 0;
    }
  • 相关阅读:
    移动端底部fixed固定定位输入框ios下不兼容
    mint-ui Picker设置指定初始值
    vue项目的mode:history模式
    更改checkbox的默认样式
    vue组件通信的几种方式
    Python运行Google App Engineer时出现的UnicodeDecodeError错误解决方案
    ActionFilterAttribute之HtmlFilter,压缩HTML代码
    MongoDB C#驱动中Query几个方法
    无需路由端口映射 花生壳6.5工程版发布
    如何让搜索引擎抓取AJAX内容?
  • 原文地址:https://www.cnblogs.com/qscqesze/p/5271013.html
Copyright © 2011-2022 走看看