zoukankan      html  css  js  c++  java
  • 【洛谷P3233】世界树

    题目

    题目链接:https://www.luogu.com.cn/problem/P3233
    世界树是一棵无比巨大的树,它伸出的枝干构成了整个世界。在这里,生存着各种各样的种族和生灵,他们共同信奉着绝对公正公平的女神艾莉森,在他们的信条里,公平是使世界树能够生生不息、持续运转的根本基石。
    世界树的形态可以用一个数学模型来描述:世界树中有 \(n\) 个种族,种族的编号分别从 \(1\)\(n\),分别生活在编号为 \(1\)\(n\) 的聚居地上,种族的编号与其聚居地的编号相同。有的聚居地之间有双向的道路相连,道路的长度为 \(1\)。保证连接的方式会形成一棵树结构,即所有的聚居地之间可以互相到达,并且不会出现环。定义两个聚居地之间的距离为连接他们的道路的长度;例如,若聚居地 \(a\)\(b\) 之间有道路,\(b\)\(c\) 之间有道路,因为每条道路长度为 \(1\) 而且又不可能出现环,所以 \(a\)\(c\) 之间的距离为 \(2\)
    出于对公平的考虑,第 \(i\) 年,世界树的国王需要授权 \(m_i\) 个种族的聚居地为临时议事处。对于某个种族 \(x\)\(x\) 为种族的编号),如果距离该种族最近的临时议事处为 \(y\)\(y\) 为议事处所在聚居地的编号),则种族 \(x\) 将接受 \(y\) 议事处的管辖(如果有多个临时议事处到该聚居地的距离一样,则 \(y\) 为其中编号最小的临时议事处)。
    现在国王想知道,在 \(q\) 年的时间里,每一年完成授权后,当年每个临时议事处将会管理多少个种族(议事处所在的聚居地也将接受该议事处管理)。 现在这个任务交给了以智慧著称的灵长类的你:程序猿。请帮国王完成这个任务吧。
    \(N\leq 300000\), \(q\leq 300000\), \(\sum^q_{i=1}m_i \leq 300000\)

    思路

    调了 5 天,细节真的很多很烦。自闭到一度想要放弃233。
    首先看见 \(m\) 的和不超过 \(3\times 10^5\),容易想到虚树。那么对于每一组询问,构建虚树后,分为 3 个部分来分别计算:

    1. 虚树上的点
    2. 虚树的结点在原树中的子树的点
    3. 虚树边上的点

    显然原树中的任意一个节点可以归属到上面三类中的一类的。

    1. 虚树上的点

    这个很好办。分别用两次 dfs 求出虚树上一个点 \(x\) 往下走和往上走能到达的最近关键节点即可。
    具体来说,设 \(dep[x]\) 表示 \(x\) 在原树中的深度,\(dis[x]\) 表示 \(x\) 到关键节点的最短距离,\(pos[x]\) 表示 \(x\) 在哪个关键节点的管辖范围之内。
    第一遍 dfs 遍历 \(x\) 的每一个子节点 \(y\),如果 \(dis[y]+dep[y]-dep[x]<dis[x]\) 或者两者相等且 \(pos[x]>pos[y]\),那么就用 \(pos[y]\) 来更新 \(pos[x]\)
    第二遍 dfs,对于 \(x\) 的父节点 \(fa\),判断 \(dis[fa]+dep[x]-dep[fa]\) 是否小于 \(dis[x]\)。其余和 1 一样。

    2.虚树的结点在原树中的子树的点

    什么意思?哪样例来说

    对于第二组询问2 7 3 6 9,以 3 号节点为例,他有三个子节点 4,7,8,其中 4,7 的子树中都有关键点,仅有 8 的子树中没有关键点,所以设 \(pos[4]=x\),那么原树中 8 节点的子树一定都归属于 \(x\)
    这一部分怎么计算呢?考虑用该节点原树中的大小减去虚树中的子树大小,因为不在虚树中的子节点一定没有关键节点后代。
    那么这一部分也计算完了。

    3.虚树边上的点

    容易发现,对于虚树中的一条边 \(y\to x\),在原树中是一条链,且链上一定存在一个节点 \(p\)\(p\) 以下的节点全部归属于 \(pos[x]\)\(p\) 以上的节点全部归属于 \(pos[y]\)
    如何求出这个 \(p\)?既然满足单调,那么倍增即可。
    注意不仅仅是这条链上的点,是这条链上的点以及他们的其他子树(不在虚树上的子树)节点一同归属。实在不是很好解释,画个图看看吧。

    那么这三个部分都解决了。清空还是最傻的办法,直接开 \(\operatorname{set}\) 记录虚树中的点。显然有更好的方法但是懒。
    细节真的很多,调样例可能都要调很久,然后交上去发现还 WA 了233。

    \[\color{white}{\texttt{主要还是 stoorzTCL}} \]

    时间复杂度 \(O(Q\log n)\)

    代码

    很丑

    #include <set>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    
    const int N=300010,LG=20,Inf=1e9;
    int dep[N],head[N],dis[N],f[N][LG+1],dfn[N],a[N],id[N],st[N],pos[N],ans[N],size[N];
    int n,Q,m,tot,top;
    bool key[N];
    set<int> vis;
    
    struct edge
    {
    	int next,to;
    }e[N*2];
    
    bool cmp(int x,int y)
    {
    	return dfn[x]<dfn[y];
    }
    
    void add(int from,int to)
    {
    	e[++tot].to=to;
    	e[tot].next=head[from];
    	head[from]=tot;
    }
    
    int lca(int x,int y)
    {
    	if (dep[x]<dep[y]) swap(x,y);
    	for (int i=LG;i>=0;i--)
    		if (dep[f[x][i]]>=dep[y]) x=f[x][i];
    	if (x==y) return x;
    	for (int i=LG;i>=0;i--)
    		if (f[x][i]!=f[y][i])
    			x=f[x][i],y=f[y][i];
    	return f[x][0];
    }
    
    void dfs1(int x,int fa)
    {
    	dfn[x]=++tot; 
    	dep[x]=dep[fa]+1; f[x][0]=fa;
    	for (int i=1;i<=LG;i++)
    		f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=head[x];~i;i=e[i].next)
    		if (e[i].to!=fa)
    		{
    			dfs1(e[i].to,x);
    			size[x]+=size[e[i].to];
    		}
    	size[x]++;
    }
    
    void build()
    {
    	top=tot=0;
    	sort(a+1,a+1+m,cmp);
    	for (int i=1;i<=m;i++)
    	{
    		int p=lca(a[i],st[top]);
    		for (;top && dep[st[top-1]]>=dep[p];top--)
    			add(st[top-1],st[top]);
    		if (st[top]!=p) add(p,st[top]),st[top]=p;
    		st[++top]=a[i];
    	}
    	for (;top>=1;top--)
    		add(st[top-1],st[top]);
    }
    
    void dfs2(int x)
    {
    	vis.insert(x); ans[x]=size[x];
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to;
    		dfs2(v);
    		int dis2=dis[v]+dep[v]-dep[x];
    		if (dis2<dis[x] || (dis2==dis[x] && pos[v]<pos[x]))
    			dis[x]=dis2,pos[x]=pos[v];
    	}
    	if (key[x]) dis[x]=0,pos[x]=x;
    }
    
    void dfs3(int x,int fa)
    {
    	int dis2=dis[fa]+dep[x]-dep[fa];
    	if (dis2<dis[x] || (dis2==dis[x] && pos[x]>pos[fa]))
    		dis[x]=dis2,pos[x]=pos[fa];
    	for (int i=head[x];~i;i=e[i].next)
    		dfs3(e[i].to,x);
    }
    
    int findson(int x,int y)
    {
    	for (int i=LG;i>=0;i--)
    		if (dep[f[y][i]]>dep[x]) y=f[y][i];
    	return y;
    }
    
    void dfs4(int x)
    {
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		int v=e[i].to,p=findson(x,v);
    		ans[x]-=size[p];
    		dfs4(v);
    	}
    	if (pos[x]!=x && x) ans[pos[x]]+=ans[x];
    }
    
    void solve(int x,int y)
    {
    	int p=x;
    	for (int i=LG;i>=0;i--)
    	{
    		int dis1=dis[x]+dep[x]-dep[f[p][i]];
    		int dis2=dis[y]+dep[f[p][i]]-dep[y];
    		if (dis1<dis2 || (dis1==dis2 && pos[x]<pos[y])) p=f[p][i];
    	}
    	ans[pos[x]]+=size[p]-size[x];
    	ans[pos[y]]+=size[findson(y,x)]-size[p];
    }
    
    void dfs5(int x)
    {
    	for (int i=head[x];~i;i=e[i].next)
    	{
    		dfs5(e[i].to);
    		solve(e[i].to,x);
    	}
    }
    
    int main()
    {
    	memset(head,-1,sizeof(head));
    	scanf("%d",&n);
    	for (int i=1,x,y;i<n;i++)
    	{
    		scanf("%d%d",&x,&y);
    		add(x,y); add(y,x);
    	}
    	tot=0; dfs1(1,0);
    	memset(head,-1,sizeof(head));
    	memset(dis,0x3f3f3f3f,sizeof(dis));
    	tot=0;
    	scanf("%d",&Q);
    	while (Q--)
    	{
    		scanf("%d",&m);
    		for (int i=1;i<=m;i++)
    		{
    			scanf("%d",&a[i]);
    			key[a[i]]=1; id[i]=a[i];
    		}
    		build();
    		dfs2(0); dfs3(0,0);  //虚树上的点 
    		dfs4(0);  //没有关键点的子树 
    		dfs5(0);  //虚树中的边 
    		for (int i=1;i<=m;i++)
    			printf("%d ",ans[id[i]]);
    		putchar(10);
    		for (set<int>::iterator it=vis.begin();it!=vis.end();it++)
                head[*it]=-1,key[*it]=0,ans[*it]=0,dis[*it]=Inf;
            vis.clear();
    	}
    	return 0;
    }
    
  • 相关阅读:
    css 的包含块 、负外边距,字体,文本行高
    从Excel中读取数据(python-xlrd)
    准确率(Precision),召回率(Recall)以及综合评价指标(F1-Measure)
    K-means算法-聚类
    用线性回归寻找到最佳拟合直线
    python多线程--优先级队列(Queue)
    python多线程--线程同步
    python多线程
    元组操作
    input()和raw_input()
  • 原文地址:https://www.cnblogs.com/stoorz/p/12466398.html
Copyright © 2011-2022 走看看