不优雅的暴力——树分块

我没想到省选 day2 宝石还可以用分块,话说当时我旁边的哥们就打了一个树分块……


分块是个极不优美的做法,难写的离谱……(当然莫队系列除外

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

本题强制在线。所以莫队被废了

看到题目让求路径颜色数,考虑复杂度比较高的分块做法(话说我一开始想的是树上主席树

树分块有很多分块方式

跟据罗剑桥的国家集训队论文,我算是勉强掌握了一种。

在树上撒\(\sqrt n\)个关键点,要求对于每个非关键点,它的\(1-\sqrt n\)级祖先中,必定存在至少一个关键点。

容易知道每存在一个关键点能保证最少存在\(\sqrt n\)个非关键点,那么全局最多有\(\sqrt n\)个关键点

而且若是沿着一个关键点向上跳,则最多跳大概\(\Theta(\sqrt n)\)就会达到最靠近根节点的关键点。

首先花费\(O(n\sqrt n)\)预处理所有关键点,然后花费\(O(\frac{n^2\sqrt n}{w})\)预处理任意两个关键点之间的颜色(用bitset

考虑询问u,v两个点,先求出lca,然后求出离他们最近的关键点。之后关键点之间的颜色数直接调用预处理,关键点与u和v之间的颜色直接暴力即可

总复杂度\(O(\frac{qn\sqrt n}{w})\)

#include <bits/stdc++.h>

using namespace std;

#define INF 1<<30
#define pb push_back
%:define ill unsigned long long 
%:define lowbit(x) (x&(-x))
%:define Int unsigned int 

const int np = 4e4 + 5;

template<typename _T>
inline void read(_T &x)
{
	x = 0;int f= 1;char s = getchar();
	while(s<'0'||s>'9'){f=1;if(s=='-')f=-1;s=getchar();}
	while('0'<=s&&s<='9'){x=(x<<3)+(x<<1)+s-'0';s=getchar();}
	x*=f;
}

int head[np] , nxt[np * 2] , ver[np * 2];
int tit;

inline void add(int x,int y)
{
	ver[++tit] = y;
	nxt[tit] = head[x];
	head[x] = tit;
}
int dep[np];
int val[np];
int pos[np];
int b[np];
int key[np],fkey[np];
int fa[np],son[np],siz[np];
bitset<np> bit[59][59];
int Top[np];

inline bool cmp(int a,int b)
{
	return dep[a] > dep[b];
}


inline void dfs_key(int x,int ff)
{
	dep[x] = dep[ff] + 1;
	fa[x] = ff;
	siz[x] = 1;
	for(int i=head[x],v;i;i=nxt[i])
	{
		v =ver[i];
		if(v == ff) continue;
		dfs_key(v,x);
		siz[x] += siz[v];
		if(siz[v] > siz[son[x]]) son[x] =v;
	}
}

inline void dfs_pf(int x,int anc,int k_)
{
	if(key[x] && k_ != x) fkey[x] = k_,k_ = x;
	Top[x] = anc;
	
	if(son[x]) dfs_pf(son[x] , anc,k_);
	for(int i=head[x],v;i;i=nxt[i])
	{
		v = ver[i];
		if(v == fa[x] || v == son[x]) continue;
		dfs_pf(v,v,k_); 
	}
}

inline int LCA(int x,int y)
{
	int fx = Top[x] ,fy = Top[y];
	while(fx != fy)
	{
		if(dep[fx] < dep[fy]) swap(x,y),swap(fx,fy);
		x = fa[fx];
		fx = Top[x];
	}
	return dep[x] < dep[y]?x:y;
}

bitset<np> bi;
inline void dfs_(int x,int k_,int ff)
{
	int posb = bi[val[x]];
	bi[val[x]] = 1;
	if(key[x]) 
	{
		if(key[x] >= k_)bit[k_][key[x]] = bit[key[x]][k_] = bi;
	}
	for(int i=head[x],v;i;i=nxt[i])
	{
		v =ver[i];
		if(v == ff) continue;
		dfs_(v,k_,x);
	}
	if(!posb) bi[val[x]] = 0;
}

inline int debug()
{
	return 1;
}

int T;
int n,m;
int key_[np];
signed main()
{
//	cout<<(4e4 /700);// * (4e4/600) * 4e4/1024/1024;
//	freopen("foo.in","r",stdin);
//	freopen("my.out","w",stdout);
//	freopen("data.in","r",stdin);
//	freopen("my.out","w",stdout);
	read(n);
	read(m);
//	T = sqrt(n);
	T = 700;
	for(int i=1;i<=n;i++) read(val[i]);
	memcpy(b +1,val +1 ,sizeof(val));
	sort(b + 1,b + 1 +n);
	int *st = b +1 ;
	int *ed = unique(b + 1,b +1 +n);
	for(int i=1;i<=n;i++) val[pos[i] = i] = lower_bound(st,ed,val[i])-b;
	for(int i=1,x,y;i<=n - 1;i++)
	{
		read(x);
		read(y);
		add(x,y);
		add(y,x);
	}
	
	dfs_key(1,0);
	
	sort(pos + 1,pos + 1 + n,cmp);
//	for(int i=1;i<=n;i++) cout<<pos[i]<<" ";
	
//	cout<<'\n';
	for(int i=1;i<=n;i++)
	{
		int x = fa[pos[i]];
		if(!x) continue;
		int g=x;
		for(int j=1;j<=T;j++)
		{
			if(key[x]) break;
			if(!fa[x]) {
				key[x] = 1;
				break;
			}
			g =x;
			x = fa[x];
		}
		if(key[x]) continue;
		key[g] = 1;
	}
	
	int top =0 ;
	for(int i=1;i<=n;i++) if(key[i]) key_[++top] = i;
	
	if(!key[1]) key[1] = 1,key_[++top] = 1;
	
	for(int i=1;i<=top;i++)
	{
		key[key_[i]] = i;
	}
//	cout<<"*";
	for(int i=1;i<=top;i++)
	dfs_(key_[i],i,0) , bi.reset();
//	return 0;
	dfs_pf(1,1,1);
	
	int u,v,la =0 ;
	
//	for(int i=1;i<=top;i++) cout<<key_[i]<<" "<<key[key_[i]]<<'\n';
//	cout<<'\n';
//	for(int i=1;i<=top;i++)
//	{
//		for(int j=1;j<=top;j++)
//		{
//			int opi = bit[i][j].count();
////			cout<<i<<" "<<j<<" "<<opi<<'\n';
//		}
//	}
//	return 0;
	bi.reset();
	int h = 1;
	while(m--)
	{
//		if(h == 2944) debug();
		read(u);
		read(v);
//		read(la);
//		int num = bi.count(); 
		u = u ^ la;
		int lca = LCA(u,v);
		
		int u_ = u,v_ = v;
		while(!key[u_] && u_ != lca) bi[val[u_]] = 1,u_ = fa[u_];
		while(!key[v_] && v_ != lca) bi[val[v_]] = 1,v_ = fa[v_];
		
		if(u_ != lca)
		{
			int cu = u_;
			while(dep[fkey[u_]] > dep[lca]) u_ = fkey[u_];/*if(fkey[u_] == u_) break;*/ 
			bi |= bit[key[u_]][key[cu]];
			
			while(u_ != lca) bi[val[u_]] = 1,u_ = fa[u_];
		}
		
		if(v_ != lca)
		{
			int cv = v_;
			while(dep[fkey[v_]] > dep[lca])  v_ = fkey[v_];/*if(fkey[v_] == v_) break;*/
			bi |= bit[key[v_]][key[cv]];
			while(v_ != lca) bi[val[v_]] = 1,v_ = fa[v_];			
		}
		bi[val[lca]] = 1;
		u = bi.count();
		printf("%d\n",u);
//		cout<<u<<'\n';
		bi.reset();
		la = u;
		h++;
	}
	
	return 0;
}

上一篇:辨析BI、数据仓库、数据湖和数据中台内涵及差异点(建议收藏)


下一篇:1.4.1 好多好多道符(题解)