其他分享
首页 > 其他分享> > BalticOI2017 Railway

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