ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

【SPOJ】32952 ADAFTBLL(树上带修莫队)

2022-01-27 13:32:05  阅读:192  来源: 互联网

标签:32952 cnt int res 1ll fa SPOJ ADAFTBLL first


原题链接

题意

给定一棵 \(n\) 个点的数,每个点都有一个权值。给出 \(q\) 次操作,有两种操作类型。

\(1.\) 给出 \(x\) 和 \(y\),将点 \(x\) 的权值修改为 \(y\)。

\(2.\) 给出点 \(u\) 和 \(v\),令 \(s\) 表示每一种从 \(u\) 号节点到 \(v\) 号节点出现的权值的次数,输出 \(\sum \dfrac{s \times (s-1)}{2}\)。

数据范围

\(1 \leq n,m \leq 10^5\),\(0 \leq a_i,y \leq 10^5\)。

思路

本题实际上就是维护队列Count on a tree II的结合。可以考虑用树上带修莫队求解

带修莫队实际上就是给询问增加了时间戳,将块长设置成 \(n^{\frac{2}{3}}\)。这样可以保证总的时间复杂度在 \(O(n^{\frac{5}{3}})\)。具体证明可以自行百度,这里不展开来讲。

树上莫队运用到了欧拉序的特点。简单来说就是在深搜遍历时先记录下当前点,等到遍历完其子树回溯时再记录下当前点。如题目样例给出的树:

记 \(first[u]\) 表示 \(u\) 在欧拉序中第一次出现的位置,\(last[u]\) 表示 \(u\) 在欧拉序中第二次出现的位置,\(seq[u]\) 表示欧拉序中第 \(u\) 个数。

按照出现了两次等于没有出现的思路。设 \(first[x]<first[y]\) ,可以发现,如果 \(x,y\) 的 LCA 是它们其中之一,那么从 \(first[x]\) 遍历到 \(first[y]\) 恰好将其中的每一个数字都出现了一次,不在路径上的点要么没有出现要么就出现了两次。而当它们的 LCA 不是其中之一时,按照 \(last[x]\) 到 \(first[y]\) 的顺序,除了 LCA 不会被遍历到,其余的都被遍历了一次。故只需要特判一下 LCA 即可。

最后,答案记得开 long long

code:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using namespace std;
const int N=2e5+10;
#define LL long long
int seq[N],top,n,m,len,h[N],lg[N],idx,fa[N][25],first[N],last[N],depth[N],a[N];
int tot,time;LL ans[N],res,cnt[N]; bool vis[N];
struct edge{int v,nex;}e[N]; void add(int u,int v){e[++idx].v=v;e[idx].nex=h[u];h[u]=idx;}
struct query{int l,r,q,t,id;}q[N];
struct update{int x,y;}c[N];
bool cmp(query a,query b)
{
	if(a.l/len!=b.l/len) return a.l/len<b.l/len;
	if(a.r/len!=b.r/len) return a.r/len<b.r/len;
	return a.t<b.t;
}
void dfs(int u,int father)
{
	first[u]=++top,seq[top]=u;
	depth[u]=depth[father]+1,fa[u][0]=father;
	for(int i=1;i<=lg[depth[u]];i++) fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int i=h[u];i;i=e[i].nex) if(e[i].v!=father) dfs(e[i].v,u);
	last[u]=++top,seq[top]=u;
}
int LCA(int x,int y)
{
	if(depth[x]<depth[y]) swap(x,y);
	while(depth[x]>depth[y]) x=fa[x][lg[depth[x]-depth[y]]-1];
	if(x==y) return x;
	for(int i=lg[depth[x]];i>=0;i--) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
void add(int x)
{
    vis[x]^=1;
	res-=cnt[a[x]]*(cnt[a[x]]-1ll)/2ll;
	cnt[a[x]]+=vis[x]?1:-1;
	res+=cnt[a[x]]*(cnt[a[x]]-1ll)/2ll;
}
int main()
{
	scanf("%d%d",&n,&m);len=pow(n,2.0/3);for(int i=1;i<=n;i++) scanf("%d",&a[i]);
	for(int u,v,i=1;i<n;i++) scanf("%d%d",&u,&v),u++,v++,add(u,v),add(v,u);
	for(int i=1;i<N;i++) lg[i]=lg[i-1]+((1<<lg[i-1])==i);dfs(1,0);
	for(int opt,x,y,i=1;i<=m;i++)
	{
		scanf("%d%d%d",&opt,&x,&y);
		if(opt==1) c[++time]=update{x+1,y};
		else
		{
		    tot++,x++,y++;if(first[x]>first[y]) swap(x,y);int z=LCA(x,y);
			if(z!=x)q[tot]=query{last[x],first[y],z,time,tot};	
			else q[tot]=query{first[x],first[y],0,time,tot};
		}
	}
	for(int i=1;i<=top;i++) printf("%d ",seq[i]-1);puts("");
	m=tot;sort(q+1,q+m+1,cmp);
	for(int i=0,j=1,t=0,k=1;k<=m;k++)
	{
		int l=q[k].l,r=q[k].r,tim=q[k].t;
		while(i<r) add(seq[++i]);
		while(i>r) add(seq[i--]);
		while(j>l) add(seq[--j]);
		while(j<l) add(seq[j++]);
		if(q[k].q) add(q[k].q);
		while(t<tim)
		{
			t++;
			int x=c[t].x;
			if(vis[x])
			{
				res-=cnt[a[x]]*(cnt[a[x]]-1ll)/2ll;
				cnt[a[x]]--;
				res+=cnt[a[x]]*(cnt[a[x]]-1ll)/2ll;
				res-=cnt[c[t].y]*(cnt[c[t].y]-1ll)/2ll;
				cnt[c[t].y]++;
				res+=cnt[c[t].y]*(cnt[c[t].y]-1ll)/2ll;
			}
			swap(a[x],c[t].y);
		}
		while(t>tim)
		{
			int x=c[t].x;
			if(vis[x])
			{
				res-=cnt[a[x]]*(cnt[a[x]]-1ll)/2ll;
				cnt[a[x]]--;
				res+=cnt[a[x]]*(cnt[a[x]]-1ll)/2ll;
				res-=cnt[c[t].y]*(cnt[c[t].y]-1ll)/2ll;
				cnt[c[t].y]++;
				res+=cnt[c[t].y]*(cnt[c[t].y]-1ll)/2ll;
			}
			swap(a[x],c[t].y);
			--t;
		}
		ans[q[k].id]=res;
		if(q[k].q) add(q[k].q);
	}
	for(int i=1;i<=m;i++) printf("%lld\n",ans[i]);
	return 0;
}

标签:32952,cnt,int,res,1ll,fa,SPOJ,ADAFTBLL,first
来源: https://www.cnblogs.com/NLCAKIOI/p/15849511.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有