首页 > 其他分享 >P7782 「MCOI-Zero / AC6-M03」 Sipli Field

P7782 「MCOI-Zero / AC6-M03」 Sipli Field

时间:2023-10-11 09:12:18浏览次数:34  
标签:2000001 Sipli sum P7782 1000001 答案 MCOI

P7782 「MCOI-Zero / AC6-M03」 Sipli Field

更好的阅读体验

单 log 淀粉做法。

回想正常淀粉计算的是树上的路径问题,但题目中要求计算经过每个点的答案,这样我们选取重心后一棵子树对另一棵子树的答案就会少算,所以我们淀粉时不仅要算根的答案,也要考虑子树间的相互贡献。

首先以根为重心 dfs 一遍统计出 \(f_i\) 表示深度为 \(i\) 的点有多少个,然后直接扫一遍计算根的答案,可以用前缀和优化到 \(\mathcal O(n)\)。

但是这样会多算两个端点都在同一子树内的答案,所以接下来对于每棵子树做同样的事减去多余的贡献。

对于子树间的答案,一个深度为 \(i\) 的点,它的贡献 \(d_i=\sum_{j=L-i}^{R-i}f_j\),这个过程也可以用前缀和优化。注意到一个儿子的路径一定也经过它的父亲,所以 \(d_i=d_i+\sum_{j\in son_i}d_j\),最后一遍树上差分统计即可。

常数巨大,dfs 了 114514 次,甚至被 \(\mathcal O(n\log^2 n)\) 吊着打/kk。

int s2[2000001],f[2000001],g[2000001],sum[1000001],ans[1000001],vis[1000001],siz[1000001],head[1000001],nex[2000001],to[2000001];
int dt,cnt,n,root,col,all,tot,L,R;
#define ca(d) (d<0?0:s2[d])
inline void add(int x,int y){to[++cnt]=y,nex[cnt]=head[x],head[x]=cnt;}
void find(int k,int fa)
{
	siz[k]=1;int maxn=0;
	for(int i=head[k];i;i=nex[i])
	{
		if(to[i]==fa||vis[to[i]])continue;
		find(to[i],k),siz[k]+=siz[to[i]],maxn=max(maxn,siz[to[i]]);
	}
	if(max(maxn,all-siz[k])<=all/2)root=k;
}
void dfs1(int k,int fa,int depth,int v)
{
	f[depth]+=v,dt=max(dt,depth);
	for(int i=head[k];i;i=nex[i])if(to[i]!=fa&&!vis[to[i]])dfs1(to[i],k,depth+1,v);
}
void dfs2(int k,int fa,int depth,int v)
{
	sum[k]+=(ca(min(dt,R-depth))-ca(min(dt,L-depth-1)))*v;
	for(int i=head[k];i;i=nex[i])if(to[i]!=fa&&!vis[to[i]])dfs2(to[i],k,depth+1,v);
}
void dfs3(int k,int fa,int depth,int v)
{
	g[depth]+=v,dt=max(dt,depth);
	for(int i=head[k];i;i=nex[i])if(to[i]!=fa&&!vis[to[i]])dfs3(to[i],k,depth+1,v);
}
void up(int k,int fa){for(int i=head[k];i;i=nex[i])if(to[i]!=fa&&!vis[to[i]])up(to[i],k),sum[k]+=sum[to[i]];}
void modify(int k,int fa)
{
	ans[k]+=sum[k],sum[k]=0;
	for(int i=head[k];i;i=nex[i])if(to[i]!=fa&&!vis[to[i]])modify(to[i],k);
}
void getsiz(int k,int fa)
{
	siz[k]=1;
	for(int i=head[k];i;i=nex[i])if(!vis[to[i]]&&to[i]!=fa)getsiz(to[i],k),siz[k]+=siz[to[i]];
}
void starch(int k,int fa)
{
	find(k,fa),k=root,getsiz(k,fa),vis[k]=1,ans[k]*=2;
	dt=0,dfs1(k,fa,0,1),s2[0]=f[0];
	for(int i=1;i<=dt;++i)s2[i]=s2[i-1]+f[i];
	for(int i=0;i<=dt;++i)ans[k]+=f[i]*(ca(min(dt,R-i))-ca(min(dt,L-i-1)));
	for(int i=head[k];i;i=nex[i])if(to[i]!=fa&&!vis[to[i]])dfs2(to[i],k,1,1);
	dfs1(k,fa,0,-1);
	for(int i=head[k];i;i=nex[i])
	{
		if(to[i]==fa||vis[to[i]])continue;
		dt=0,dfs3(to[i],k,1,1),s2[0]=g[0];
		for(int i=1;i<=dt;++i)s2[i]=s2[i-1]+g[i];
		for(int i=1;i<=dt;++i)ans[k]-=g[i]*(ca(min(dt,R-i))-ca(min(dt,L-i-1)));
		dfs3(to[i],k,1,-1);
		dfs2(to[i],k,1,-1);
		up(to[i],k),modify(to[i],k);
	}
	ans[k]/=2;int kk=k;
	for(int i=head[kk];i;i=nex[i])if(!vis[to[i]]&&to[i]!=fa)all=siz[to[i]],starch(to[i],kk);
}
void mian()
{
	read(n,L,R);int x;
	for(int i=2;i<=n;++i)read(x),add(x,i),add(i,x);
	all=n,starch(1,0);
	for(int i=1;i<=n;++i)write(ans[i],'\n');
}

标签:2000001,Sipli,sum,P7782,1000001,答案,MCOI
From: https://www.cnblogs.com/WrongAnswer90-home/p/17756232.html

相关文章

  • P7568 「MCOI-05」追杀
    原题首先这题比较重要的一点是要往暴力去想,因为我们发现\(m\)的值很小,而且这个操作是没有合并性的,即不能通过是否存在某个操作来判断全部成员的生存情况我们先考虑一个比较暴力的做法,暴力枚举对于每个点\(u\)如果在\(t\)时刻死亡会影响哪些操作,对于操作我们暂时先暴力的\(O(n)\)......
  • 「MCOI-05」追杀
    「MCOI-05」追杀洛谷题目描述DreamSMP具有\(m\)位玩家,编号为\(1\)至\(m\)。初始时,每一位玩家生命数量为\(3\)。一位玩家公认活着(canonicallyalive)当且仅当生命值非零。DreamSMP经常发生大型战争,于是会有玩家杀(PvP)别的玩家。对于活着玩家\(u\)与\(v\),如果\(......
  • BMCOIN: 清单和工艺路线接口
      导入BOM出错。运行“清单和工艺路线接口”请求。路径:BOM>>清单和工艺路线接口。解决方式:Updateinv.mtl_system_items_bSetreplenish_to_order_flag=‘Y’–按订单装配WHEREINVENTORY_ITEM_ID=2054193 --料号#150305130013AM*2054192ANDORGAINIZATION_ID=......
  • P6812 「MCOI-02」Ancestor 先辈
    这个题真的是太恶心了……一份同样的代码,在不同的时间提交,一次能过,一次差一点点……第35个点是真nm恶心……(就挂在这个点上:一次950+ms,一次1.00s),刚好小号过了,大号没过……......
  • 题解 LGP7888【「MCOI-06」Distinct Subsequences】
    problem给定一个由小写字符构成的字符串\(S\)。令一个字符串的价值为该串的本质不同非空子序列个数,其中子序列可以为整体。求\(S\)所有子序列的价值和。答案对\(10^......
  • P8283 「MCOI-08」Dantalion 解题报告
    P8283「MCOI-08」Dantalion解题报告:最近好像有很多人做这道题,把这题题解发一下吧。可能说的比较啰嗦,见谅。题意给定序列\(a\),\(q\)次询问一个区间有多少个子区间在......
  • 洛谷P6812「MCOI-02」Ancestor 先辈
    洛谷P6812对于题目的区间加法明显可以用线段树或树状数组进行并且由题可得,先辈序列即为不下降序列,需满足ai<aj&&i<j判断一个序列是否为先辈我们比较的是一个元素和前一......