HDU 5296 Annoying problem dfs序 lca set

Annoying problem

Problem 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
 
Author
FZUACM
 

题意:

给出一棵树,每个边都有一个权值,现在有一个空的集合,两种操作,

1 x吧x节点放到集合中(如果还没放入)

2 x把x节点从集合中拿出来(已放入)。

每次操作后输出最小的边权和,保证这些边可以将这些点连起来。

题解:

#include <iostream>
#include <cstdio>
#include <cmath>
#include <cstring>
#include <algorithm>
#include<vector>
#include<set>
using namespace std;
const int N = 1e5+20, M = 30005, mod = 1000000007, inf = 0x3f3f3f3f;
typedef long long ll;
//不同为1,相同为0
int in[N],dis[N],head[N],t,vis[N],fa[N][18],deep[N],cas=1,ff[N],cur,v[N];
vector<pair<int ,int > >G[N];
set<int >s;
struct edge{int to,next,v;}e[N*4];
void add(int u,int v,int val) {e[t].to = v;e[t].next = head[u];e[t].v = val; head[u]=t++;}
void dfs(int x,int f) {
    in[x] = cur;
    ff[cur] = x;
    cur++;
    for(int i=0;i<G[x].size();i++) {
        if(G[x][i].first!=f) {
            dis[G[x][i].first] = dis[x]+G[x][i].second;
            dfs(G[x][i].first,x);
        }
    }
}
void dfs1(int x) {
    vis[x] =1;
    for(int i=1;i<=17;i++) {
        if(deep[x] < (1<<i)) break;
        fa[x][i] = fa[fa[x][i-1]][i-1];
    }
    for(int i=head[x];i;i=e[i].next) {
        if(vis[e[i].to]) continue;
        deep[e[i].to] = deep[x]+1;
        fa[e[i].to][0] = x;
        dfs1(e[i].to);
    }
}
int lca(int x,int y) {
    if(deep[x] < deep[y]) swap(x,y);
    int t = deep[x] - deep[y];
    for(int i=0;i<=17;i++)
        if(t&(1<<i)) x = fa[x][i];
    for(int i=17;i>=0;i--)
    if(fa[x][i]!=fa[y][i]) {
        x = fa[x][i];
        y = fa[y][i];
    }
    if(x==y) return x;
    return fa[x][0];
}
int solve(int u){
if (s.empty())
  return 0;
 int x, y;
   set<int>::iterator it = s.lower_bound(u), itx = it;
 itx--;
 if (it == s.end() || it == s.begin()) {
  it = s.begin();
  itx = s.end();
  itx--;
 }
 y = (*it);
 x = (*itx);
  y = ff[y];
 x =ff[x];
 u=ff[u];
 //cout<<u<<" "<<x<<" "<<y<<endl;
    return dis[u]-dis[lca(u,x)]-dis[lca(u,y)]+dis[lca(x,y)];
}
void init() {
    int n,m;
    for(int i=0;i<N;i++) G[i].clear();s.clear();
    memset(head,0,sizeof(head));
    memset(vis,0,sizeof(vis));
    memset(dis,0,sizeof(dis));
     memset(v,0,sizeof(v));
    memset(deep,0,sizeof(deep));
    memset(ff,0,sizeof(ff));
     memset(fa,0,sizeof(fa));
     memset(in,0,sizeof(in));
    cur=1;t=1;
    scanf("%d%d",&n,&m);
    for(int i=1;i<=n-1;i++) {
        int a,b,c;
        scanf("%d%d%d",&a,&b,&c);
        G[a].push_back(make_pair(b,c));
        G[b].push_back(make_pair(a,c));
        add(a,b,c);
        add(b,a,c);
    }
    dfs(1,1);dfs1(1);int ans=0;
    printf("Case #%d:
",cas++);
    for(int i=1;i<=m;i++) {
        int a,b;
        scanf("%d%d",&a,&b);
        b=in[b];
        if(a==1) {
             if(!v[b]){
                             v[b]=1;
                        if(s.size()==0){
                            s.insert(b);
                        }
                        else{
                            ans+=solve(b);
                            s.insert(b);
                        }
                    }
        }
        else {
              if(v[b]){
                                v[b]=0;
                                s.erase(b);
                                if(s.size()!=0){
                                    ans-=solve(b);
                                }
                    }
        }
        printf("%d
",ans);
    }
}
int main() {int T;
    scanf("%d",&T);
    while(T--) {
        init();
    }
    return 0;
}
原文地址:https://www.cnblogs.com/zxhl/p/5273290.html