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\n",ans/2);
    }
}

int main()
{
    int t;scanf("%d",&t);
    for(int i=1;i<=t;i++)
    {
        printf("Case #%d:\n",i);
        solve();
    }
    return 0;
}
posted @ 2016-03-13 00:03  qscqesze  阅读(379)  评论(0编辑  收藏  举报