《牛客IOI周赛17-提高组A》
作者:互联网
题意:对于题意可以分解为.
有n个点,由n-1条白色的边连接,同时又有着m条边.
因为这里说到了白色的边都不重复也不缠绕,显然是n-1条边构成树边.
然后有m条非树边。然后问我们删去一条树边和一条非树边使树分为两部分。这条边完全断开.
思路:
我们可以从每条树边出发。
对于每条树边。
如果没有非树边覆盖到它.那么删去所有中任意的非树边都可以.即m种方案. 如果有一条非树边覆盖到它,那么只有删去这条树边才可以.即1种方案. 如果有两条及以上的非树边覆盖到它,那么删去非树边中的任意一条都不行,依旧会连通.所以此时方案为0. 统计树边的覆盖情况采用树上差分的边差分. Code:#include<bits/stdc++.h> using namespace std; typedef long long LL; typedef pair<int,int> pii; const int N = 2e5+5; const int M = 1e6+5; const int Mod = 1e9+7; #define pi acos(-1) #define INF 1e8 #define INM INT_MIN #define pb(a) push_back(a) #define mk(a,b) make_pair(a,b) #define dbg(x) cout << "now this num is " << x << endl; #define met0(axx) memset(axx,0,sizeof(axx)); #define metf(axx) memset(axx,-1,sizeof(axx)); #define sd(ax) scanf("%d",&ax) #define sld(ax) scanf("%lld",&ax) #define sldd(ax,bx) scanf("%lld %lld",&ax,&bx) #define sdd(ax,bx) scanf("%d %d",&ax,&bx) #define sddd(ax,bx,cx) scanf("%d %d %d",&ax,&bx,&cx) #define sfd(ax) scanf("%lf",&ax) #define sfdd(ax,bx) scanf("%lf %lf",&ax,&bx) #define pr(a) printf("%d\n",a) #define plr(a) printf("%lld\n",a) /* 对于一条树边. 如果没有非树边覆盖到它.那么所有的非树边都可以.即m. 如果有一条非树边覆盖到它,那么删去这条树边.即1. 如果有两条及以上的非树边覆盖到它,那么删去非树边中的任意一条都不行,依旧会连通.所以此时方案为0 */ vector<int> G[N]; int n,m,dep[N],f[N][25],lg[25],c[N];//i到父节点的边被多少条非树边覆盖 LL ans = 0; void init() { lg[0] = 1;for(int i=1;i<25;++i) lg[i] = lg[i-1]<<1; } void dfs(int u,int fa) { dep[u] = dep[fa]+1; f[u][0] = fa; for(int i=1;i<25;++i) f[u][i] = f[f[u][i-1]][i-1]; for(auto v:G[u]) if(v != fa) dfs(v,u); } int Lca(int x,int y) { if(dep[x] < dep[y]) swap(x,y); int dix = dep[x]-dep[y]; for(int i=24;i>=0;--i) { if(lg[i] <= dix) dix -= lg[i],x = f[x][i]; } if(x == y) return x; for(int i=24;i>=0;--i) { if(lg[i] <= dep[x] && f[x][i] != f[y][i]) x = f[x][i],y = f[y][i]; } return f[x][0]; } void dfs1(int u,int fa) { for(auto v:G[u]) { if(v == fa) continue; dfs1(v,u); c[u] += c[v]; if(c[v] == 0) ans += m; else if(c[v] == 1) ans++; //else都不能. } } void slove() { init(); sdd(n,m); for(int i=1;i<n;++i) { int u,v;sdd(u,v); G[u].pb(v),G[v].pb(u); } dfs(1,0); for(int i=1;i<=m;++i) { int u,v;sdd(u,v); c[u]++,c[v]++,c[Lca(u,v)]-=2; } dfs1(1,0); plr(ans); } int main() { slove(); system("pause"); return 0; }View Code
标签:lg,17,树边,边覆盖,牛客,int,IOI,删去,define 来源: https://www.cnblogs.com/zwjzwj/p/13061911.html