1 条题解
-
0
设某个副部长要连的点集为 ,要求这个副部长所选的边。
我们会发现,如果将 中所有元素按 序排列,然后依次相连,并且第一个元素和最后一个元素相连,就会形成一个环。
而环上的边就是副部长要选的,并且都会被重复计算两次。
为什么按 序排序?因为按这样的话,如果到某个 之前的所有点都在同一条链上,而 在另一条链上,那 一定是一条链的结尾, 一定是另一条链的开头。
那么所有链就会头尾相连,必定形成一个每条边都重复两次的环。
然后用树上差分和倍增维护一下就行了。
代码:
#include<bits/stdc++.h> #define N 100005 using namespace std; int n,m,K,s,u,v,h[N],d[N]; int head[N],nxt[N<<1],to[N<<1],cnt; inline void add(int x,int y){ to[++cnt]=y; nxt[cnt]=head[x]; head[x]=cnt; } int fa[N][21],dep[N],id[N],tot; void dfs(int k){ for(int i(1);i<=20;++i) fa[k][i]=fa[fa[k][i-1]][i-1]; id[k]=++tot; for(int i(head[k]);i;i=nxt[i]) if(!id[to[i]]){ fa[to[i]][0]=k; dep[to[i]]=dep[k]+1; dfs(to[i]); } } inline int LCA(int x,int y){ if(dep[x]<dep[y]) swap(x,y); for(int i(20);~i;--i){ if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if(x==y) return x; } for(int i(20);~i;--i) if(fa[x][i]^fa[y][i]){ x=fa[x][i]; y=fa[y][i]; } return fa[x][0]; } inline bool cmp(const int&a,const int&b){ return id[a]<id[b]; } vector <int> vec; void CCF(int k,int f){ for(int i(head[k]);i;i=nxt[i]) if(to[i]^f){ CCF(to[i],k); d[k]+=d[to[i]]; if(d[to[i]]>=2*K) vec.push_back(i+1>>1); } } int main(){ scanf("%d%d%d",&n,&m,&K); for(int i(1);i<n;++i){ scanf("%d%d",&u,&v); add(u,v);add(v,u); } dep[1]=1;dfs(1); for(int i(1);i<=m;++i){ scanf("%d",&s); for(int j(1);j<=s;++j) scanf("%d",&h[j]); sort(h+1,h+1+s,cmp); for(int j(1);j<s;++j){ ++d[h[j]]; ++d[h[j+1]]; d[LCA(h[j],h[j+1])]-=2; } ++d[h[1]]; ++d[h[s]]; d[LCA(h[1],h[s])]-=2; } CCF(1,0);printf("%d\n",vec.size());sort(vec.begin(),vec.end()); for(int i(0);i<vec.size();++i) printf("%d ",vec[i]);puts(""); return 0; }
- 1
信息
- ID
- 10559
- 时间
- 1000ms
- 内存
- 256MiB
- 难度
- 10
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者