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 ?
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)
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.
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:\n",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\n",ans); } } int main() {int T; scanf("%d",&T); while(T--) { init(); } return 0; }