Nowcoder挑战赛39F(模板树上莫队)

Nowcoder挑战赛39F(模板树上莫队)

题意:

给定一棵树,求两点路径上的不同权值个数和权值是k的倍数的个数

分析:

第二问可以直接离线询问,暴力\(n\sqrt{n}\)枚举因数更新答案,路径作差

第一问是树上莫队模板题

树上莫队:在 括号序列 上跑莫队,对于单链和双链要分类讨论,更改权值上也有细微差别,还要特判LCA的情况

合理压行和利用C++11有效缩短代码

不知道官方题解是啥么东西,复杂度就是\(O(m\sqrt{n})\),而且上界很松

const int N=1e5+10;

int n,m,len,a[N];
vector <int> G[N],Fac[N];
struct Que{ int x,k,id; };
vector <Que> Q[N];
struct Node{ int l,r,lca,id; } A[N];
int ans[N],dep[N],fa[N][20];
int line[N<<1],L[N],R[N],dfn;

void pre_dfs(int u,int f) {
	line[L[u]=++dfn]=u,fa[u][0]=f;
	rep(i,1,17) fa[u][i]=fa[fa[u][i-1]][i-1];
	for(int v:G[u]) if(v!=f) dep[v]=dep[u]+1,pre_dfs(v,u);
	line[R[u]=++dfn]=u;
}
int LCA(int x,int y){
	if(dep[x]<dep[y]) swap(x,y);
	for(int i=0,del=dep[x]-dep[y];(1<<i)<=del;++i) if(del&(1<<i)) x=fa[x][i];
	if(x==y) return x;
	drep(i,17,0) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}

int vis[N],cnt[N],Now;
void Add(int x){ if((cnt[x]++)==0) Now++; }
void Del(int x){ if((--cnt[x])==0) Now--; }
void Upd(int x){ vis[x]?Del(a[x]):Add(a[x]),vis[x]^=1; }

void dfs(int u,int f) {
	for(int t:Fac[a[u]]) cnt[t]++;
	for(Que t:Q[u]) ans[t.id]+=cnt[t.x]*t.k;
	for(int v:G[u]) if(v!=f) dfs(v,u);
	for(int t:Fac[a[u]]) cnt[t]--;
}

int main(){
	rep(i,1,N-1) for(int j=i;j<N;j+=i) Fac[j].pb(i);
	rep(kase,1,rd()) {
		n=rd();
		rep(i,1,n) G[i].clear(),Q[i].clear(),vis[i]=0;
		rep(i,1,n) a[i]=rd();
		rep(i,2,n) {
			int u=rd(),v=rd();
			G[u].pb(v),G[v].pb(u);
		}
		dfn=0,pre_dfs(1,0);
		len=sqrt(n*2);
		rep(i,1,m=rd()) {
			int x=rd(),y=rd(),z=rd(),lca=LCA(x,y);
			if(L[x]>L[y]) swap(x,y);
			if(lca==x) A[i]=(Node){L[x],L[y],0,i};
			else A[i]=(Node){R[x],L[y],lca,i};
			Q[x].pb((Que){z,1,i}),Q[y].pb((Que){z,1,i});
			Q[lca].pb((Que){z,-1,i}),Q[fa[lca][0]].pb((Que){z,-1,i});
		}
		rep(i,1,m) ans[i]=0;
		dfs(1,0);
		sort(A+1,A+m+1,[&](Node x,Node y){ return x.l/len<y.l/len||(x.l/len==y.l/len && x.r<y.r);});
		int l=1,r=0;
		rep(i,1,m) {
			while(l<A[i].l) Upd(line[l++]);
			while(l>A[i].l) Upd(line[--l]);
			while(r>A[i].r) Upd(line[r--]);
			while(r<A[i].r) Upd(line[++r]);
			if(A[i].lca) Upd(A[i].lca);
			ans[A[i].id]^=Now;
			if(A[i].lca) Upd(A[i].lca);
		}
		rep(i,1,n) cnt[a[i]]=0;
		Now=0;
		printf("Case #%d:\n",kase);
		rep(i,1,m) printf("%d\n",ans[i]);
	}
}

原文地址:https://www.cnblogs.com/chasedeath/p/12724013.html