热身训练1 ping ping ping
题意:
一棵树,n+1 个节点,以0号节点为根,给出端点(a,b),节点a到节点b的路径上,至少有一个点是“坏掉的”,求“坏掉的点”最少
分析:
Step1:贪心
每次给出的两个端点,我们可以得到他俩的lca,画一下图我们即可知道,lca深度越深,下面的点就越需要单独选一下,并且选了之后,对lca在上面的点影响不大
同时,我们每次选一段路径上的点时,肯定选深度较低的,这样最优
Step2:线段树标记选过的点
我们选过的节点,那么它的子树我们都可以不用选了
用DFS序+线段树,标记。
easy~~~
#include<bits/stdc++.h> using namespace std; #define re register int #define LL long long const int N=30005, M=50005; int tt, las[N], nt[M], ed[M]; inline void add(const int x, const int y) { ed[++tt]=y; nt[tt]=las[x]; las[x]=tt; } int dep[N], in[N], ou[N], fa[N][25], total; void DFS(const int x, const int FA) { dep[x]=dep[FA]+1; in[x]=++total; fa[x][0]=FA; for(re i=1;i<=20;++i) fa[x][i] = fa[fa[x][i-1]][i-1]; for(re i=las[x];i;i=nt[i]) { int v=ed[i]; if(v != FA) { DFS(v, x); } } ou[x]=total; } inline int lca(int x,int y) { if(dep[x] < dep[y]) swap(x, y); int del = (dep[x] - dep[y]); for(re i=0;i<=20;++i) if(del&(1<<i)) x = fa[x][i]; if(x == y) return x; for(re i=20;i >= 0;--i) if(fa[x][i] != fa[y][i]) x = fa[x][i], y = fa[y][i]; return fa[x][0]; } int n, m, ans; struct rdin{int a, b, ca;}ask[50005]; bool cmp(const rdin&x, const rdin&y) { return dep[x.ca] > dep[y.ca]; } struct segment{int a, b, v;}tr[N<<3]; inline void build(const int p, const int x, const int y) { tr[p]=(segment){x, y, 0}; if(x != y) { int mid=(x+y)>>1; build(p<<1, x, mid); build(p<<1|1, mid+1, y); } } void modi(const int p, const int x, const int y) { if(x <= tr[p].a && tr[p].b <= y) { tr[p].v = 1; return; } int mid=(tr[p].a+tr[p].b)>>1; if(x <= mid) modi(p<<1, x, y); if(y > mid) modi(p<<1|1, x, y); tr[p].v = (tr[p<<1].v && tr[p<<1|1].v); } int query(const int p, const int x) { if(tr[p].v == 1) { return 1; } if(tr[p].a == x && x == tr[p].b) { return tr[p].v; } int mid=(tr[p].a+tr[p].b)>>1; if(x <= mid) return query(p<<1, x); else return query(p<<1|1, x); } signed main() { while(scanf("%d",&n) != EOF) { ans = tt = total = 0; memset(las, 0, sizeof(las)); for(re i=1;i<=n;++i) { int x, y; scanf("%d%d",&x,&y); x++; y++; add(x, y); add(y, x); } n++; DFS(1, 0); scanf("%d",&m); for(re i=1;i<=m;++i) { scanf("%d%d",&ask[i].a,&ask[i].b); ask[i].a++; ask[i].b++; ask[i].ca = lca(ask[i].a, ask[i].b); } sort(ask+1, ask+1+m, cmp); build(1, 1, n+5); for(re i=1;i<=m;++i) { int a=query(1, in[ask[i].a]); int b=query(1, in[ask[i].b]); if(a==0 && b==0) { modi(1, in[ask[i].ca], ou[ask[i].ca]); ans++; } } printf("%d\n", ans); } }