BalticOI2017 Railway
作者:互联网
看了一眼网上的题解,好像我的做法没有出现(?),并且我的做法好像比较简单易懂(?),不用虚树也不用线段树维护
不难想到,我们可以对于每个副部长的点连成的最短路径(即这个路径里的每条边都是必要的)上+1,然后看有哪些路是\(>=k\)的,但是我们需要不重复不遗漏的把这个路径都走到。于是我们考虑把这些点树链剖分,按照树剖的顺序排个序,因为我们走路径一定是要按照某种顺序的,可以想象成,把一条链抽出来,两点距离就是最短距离(感性理解一下),然后每次对相邻接点进行树上差分,即当前点++,lca--,就行了,但是要注意的是,他们这些点的 lca 是要放在最后单独处理一下的
最后dfs求子树和,统计一下答案就行了
点击查看代码
//CAN'T FORGET
//CAN'T FORGET
//CAN'T FORGET
//#pragma GCC optimize("Ofst")
#include<bits/stdc++.h>
using namespace std;
#define _ 0
const int maxn=1e6+5;
const int inf=0x3f3f3f3f;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while(ch<'0'||ch>'9')
{
if(ch=='-')
f=-1;
ch=getchar();
}
while(ch>='0'&&ch<='9')
{
x=(x<<1)+(x<<3)+(ch^48);
ch=getchar();
}
return x*f;
}
struct node{
int to,nxt;
}edge[maxn];
int head[maxn],tot;
void addedge(int u,int v)
{
edge[++tot].to=v;
edge[tot].nxt=head[u];
head[u]=tot;
}
int sz[maxn],dep[maxn],f[maxn],son[maxn];
int top[maxn];
void dfs1(int x,int fa)
{
sz[x]=1;
dep[x]=dep[fa]+1;
for(int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if(y==fa)
continue;
f[y]=x;
dfs1(y,x);
sz[x]+=sz[y];
if(sz[son[x]]<sz[y])
son[x]=y;
}
}
int dfn[maxn],id;
void dfs2(int x,int tp)
{
dfn[x]=++id;
top[x]=tp;
if(son[x]!=0)
dfs2(son[x],tp);
for(int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if(y==f[x]||y==son[x])
continue;
dfs2(y,y);
}
}
int getlca(int u,int v)
{
while(top[u]!=top[v])
{
if(dep[top[u]]>=dep[top[v]])
u=f[top[u]];
else
v=f[top[v]];
}
if(dep[u]<dep[v])
return u;
return v;
}
int sum[maxn],ans[maxn],nm;
void dfs3(int x,int fa)
{
for(int i=head[x];i;i=edge[i].nxt)
{
int y=edge[i].to;
if(y==fa)
continue;
dfs3(y,x);
sum[x]+=sum[y];
}
}
int s[maxn],x[maxn];
map<pair<int,int>,int> dy;
bool cmp(int a,int b)
{
return dfn[a]<dfn[b];
}
int main(){
ios::sync_with_stdio(false);
cin.tie(0);
cout.tie(0);
freopen("railway.in","r",stdin);
freopen("railway.out","w",stdout);
int n,m,k;
cin>>n>>m>>k;
for(int i=1;i<=n-1;i++)
{
int u,v;
cin>>u>>v;
addedge(u,v);
addedge(v,u);
dy[make_pair(u,v)]=i;
dy[make_pair(v,u)]=i;
}
dfs1(1,0);
dfs2(1,1);
for(int i=1;i<=m;i++)
{
cin>>s[i];
for(int j=1;j<=s[i];j++)
cin>>x[j];
sort(x+1,x+s[i]+1,cmp);
sum[x[1]]++;
int lca=x[1];
for(int j=2;j<=s[i];j++)
{
sum[x[j]]++;
int lc=getlca(x[j-1],x[j]);
sum[lc]--;
lca=getlca(lca,x[j]);
}
sum[lca]--;
}
dfs3(1,0);
for(int i=2;i<=n;i++)
if(sum[i]>=k)
ans[++nm]=dy[make_pair(f[i],i)];
sort(ans+1,ans+nm+1);
cout<<nm<<endl;
for(int i=1;i<=nm;i++)
cout<<ans[i]<<" ";
cout<<endl;
return ~~(0^_^0);
}
/*
Notes:
1.看所有题目
2.注意数据范围
3.想想自己还能做什么而不是做了什么
4.看清题目!!!
5.记得把调试代码删掉!!!!
6.longlong时 1要写成1ll
7.Think twice code once, think once code forever!
*/
标签:ch,FORGET,int,BalticOI2017,dy,++,lca,Railway 来源: https://www.cnblogs.com/zxi8-may/p/16342659.html