P6177 Count on a tree II/【模板】树分块

题目链接

题意:

一棵树上每个结点都有一个值,q次询问,每次询问 U—>V 路径上有多少个不同的值

题解:

树分块+bitset能过,还挺快的。但是不开O2的话要算一下块的大小,大一点超内存,小一点超时

#include<iostream>
#include<sstream>
#include<string>
#include<queue>
#include<map>
#include<unordered_map>
#include<set>
#include<vector>
#include<stack>
#include <utility>
#include<list>
#include<bitset>
#include<algorithm>
#include<cstdio>
#include<cmath>
#include<cstdlib>
#include<cstring>
#include<iomanip>
#include<time.h>
#include<random>
using namespace std;
#include<ext/pb_ds/priority_queue.hpp>
#include<ext/pb_ds/tree_policy.hpp>
#include<ext/pb_ds/assoc_container.hpp>
#include<ext/pb_ds/hash_policy.hpp>
using namespace __gnu_pbds;
#include<ext/rope>
using namespace __gnu_cxx;
 
#define PI acos(-1.0)
#define eps 1e-9
#define lowbit(a) ((a)&-(a))


const int mod = 1e9+7;
int qpow(int a,int b){
	int ans=1;
	while(b){
		if(b&1)ans=(ans*a)%mod;
		a=(a*a)%mod;
		b>>=1;
	}
	return ans;
}
const int INF = 0x3f3f3f3f;
const int N = 4e4+10;
struct edge{
	int to,next;
}e[N<<1];
int head[N],cnt;
void add(int u,int v){
	e[++cnt]={v,head[u]}; head[u]=cnt; swap(u,v);
	e[++cnt]={v,head[u]}; head[u]=cnt;
}
int B=275,tot,last;
int a[N],lsh[N],lg[N];
int f[N][20],dep[N],nxt[146][146],id[N];
bitset<N>bt[146][146],tmp;

int dfs(int u,int fa){
	f[u][0]=fa,dep[u]=dep[fa]+1;
	for(int i=1;i<=lg[dep[u]];i++)f[u][i]=f[f[u][i-1]][i-1];
	int madep=0;
	for(int i=head[u];i;i=e[i].next){
		int v=e[i].to;
		if(v!=fa)madep=max(madep,dfs(v,u));
	}
	if(madep>=B)id[u]=++tot,madep=0;
	return madep+1;
}
void dfs2(int x,int y){
	if(id[x]){
		nxt[id[x]][0]=x,nxt[id[x]][1]=y;
		for(int i=x;i!=y;i=f[i][0])bt[id[x]][id[y]][a[i]]=1;
		bt[id[x]][id[y]][a[y]]=1;
		for(int i=2,z;i<=145;i++){
			z=nxt[id[x]][i]=nxt[id[y]][i-1];
			bt[id[x]][id[z]]|=bt[id[x]][id[y]];
			bt[id[x]][id[z]]|=bt[id[y]][id[z]];
		}
		y=x;
	}
	for(int i=head[x];i;i=e[i].next){
		int v=e[i].to;
		if(v!=f[x][0])dfs2(v,y); 
	}
}
int lca(int x,int y){
	if(dep[x]<dep[y])swap(x,y);
	while(dep[x]>dep[y])x=f[x][lg[dep[x]-dep[y]]-1];
	if(x==y)return x;
	for(int i=lg[dep[x]]-1;i>=0;--i)if(f[x][i]!=f[y][i])
		x=f[x][i],y=f[y][i];
	return f[x][0];
}
#define endl '\n'
signed main(){
	std::ios::sync_with_stdio(false);
	cin.tie(0),cout.tie(0);
	int n,q; cin>>n>>q;
	for(int i=1;i<=n;i++)cin>>a[i],lsh[i]=a[i];
	sort(lsh+1,lsh+1+n); int m=unique(lsh+1,lsh+1+n)-lsh-1;
	for(int i=1;i<=n;i++)a[i]=lower_bound(lsh+1,lsh+1+m,a[i])-lsh;
	for(int i=1;i<n;i++){
		lg[i]=lg[i-1]+(1<<lg[i-1]==i);
		int u,v; cin>>u>>v;
		add(u,v);
	}
	dfs(1,0); dfs2(1,0);
	while(q--){
		int x,y,p; cin>>x>>y;
		x^=last; p=lca(x,y);
		tmp.reset(); tmp[a[p]]=1;
		for(;!id[x]&&x!=p;x=f[x][0]) tmp[a[x]]=1;
		for(;!id[y]&&y!=p;y=f[y][0]) tmp[a[y]]=1;
		if(id[x]){
			for(int i=1;;i++)if(dep[nxt[id[x]][i]]<dep[p]){
				tmp|=bt[id[x]][id[nxt[id[x]][i-1]]];
				x=nxt[id[x]][i-1];
				break;
			}
		}
		if(id[y]){
			for(int i=1;;i++)if(dep[nxt[id[y]][i]]<dep[p]){
				tmp|=bt[id[y]][id[nxt[id[y]][i-1]]];
				y=nxt[id[y]][i-1];
				break;
			}
		}
		for(;x!=p;x=f[x][0]) tmp[a[x]]=1;
		for(;y!=p;y=f[y][0]) tmp[a[y]]=1;
		cout<<(last=tmp.count())<<endl;
	}
	
}
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值