csp模拟(个鬼)迷雾华光【树分块】【虚树】【树上莫队】【主席树】

传送门

两种做法,一种是树分块+虚树,一种是树分块+主席树

我使用树分块+虚树,感觉好写一点qwq

 

预处理:

随机\sqrt n个关键点(当然是保证两两距离在\sqrt n左右),然后把关键点的lca也点成关键点。即分块。

求出每个点向上走第一个关键点,每个点子树中(包括自己)第一个关键点,每个关键点到根路径上的颜色信息和(n\sqrt n),任意两个关键点路径上的众数和次数(n)。

有性质:如果一个点不是关键点,则其子树中最多只有一个子树有关键点。(否则它会成为一个lca)

对于分块,我们从叶子节点开始,一旦走出dis>\sqrt n,则将当前点设为关键点。

然后虚树的建立方式找lca。

从每个关键点dfs一遍整棵树(n\sqrt n),找出两两关键点的答案。

找向上走第一个关键点就像树链剖分第二个dfs那样dfs一遍。

找向下走第一个关键点就从子树继承dfs一遍。

 

对于询问:

首先求出两个点的lca。(倍增也很快,当然可以st表O(1)求,下面讲)

对于询问,有三种可能。

第一种:两个点路径上没有关键点或只有一个关键点在lca上。(体现是up[u]==up[v])

这时我们暴力跳就是了。直接统计答案。

第二种:某个点到lca的路径上有关键点。另一个点没有。(体现是某个点的dep[up]小于dep[lca])

如果设u~lca的路径上没有关键点,这时我们要跳三段暴力。

分别是u~lca,lca~down[lca],v~up[v]。很明显如果路径上有多个关键点,那这些关键点之间的信息我们没有获取。

因为已经预处理,这些可以待会儿直接查询。

第三种:两个点到lca的路径上都有关键点。这时我们只需要各自暴力跳到up,然后留到待会儿查询即可。

 

对于第二种和第三种,最后应该查询关键点之间的信息。

 

最后记得清空数组。差不多应该说完了。

 

方法2:主席树+树分块。from FSYolanda

对于关键点,不取lca做关键点。同样预处理每对关键点之间的答案。

然后对于暴力跳的部分,主席树查询即可。复杂度多了一个log,但有效分块的话log可以进根号下。

对于询问暴力部分,主席树查询。其它不变。

这个方法好巧妙,听起来就很好写的鸭子。但我懒得写了qwq好累

在woj交记得开栈,100M才够的鸭子,,

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define pb push_back
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();
	}return cnt*f;
}
//clock_t st,ed;
vector<int> key;
const int N=80003,M=753;
int Type,n,a[N][3],LCA[M][M];
int up[N],down[N];
int val[M][N];//关键点颜色。
int sum[M][N];// 关键点到根颜色信息;
int vis[N];
int cur[N];//临时颜色信息数组 
int Color[M][M],Size[M][M];//关键点对间答案 
int first[N],nxt[N<<1],to[N<<1],tot;
inline void add(int a,int b){
	nxt[++tot]=first[a];first[a]=tot;to[tot]=b;
}int q,last;
inline void modify(int &SIZE,int &COLOR,int NSIZE,int NCOLOR){
	if(SIZE<=NSIZE){
		if(SIZE<NSIZE){
			SIZE=NSIZE;COLOR=NCOLOR;
		}else if(NCOLOR<COLOR){
			COLOR=NCOLOR;
		}
	}
}
namespace TREE{
	int fa[N][20],dep[N];
	int dfn[N],cntdfn;
	int cntt,fir[N],st[20][(N<<1)+1],lg[(N<<1)+1];
	bool cm(int a,int b){
		return dep[a]>dep[b];
	}
	bool cmm(int a,int b){
		return dfn[a]<dfn[b];
	}
	void dfs(int u,int faa){
		dep[u]=dep[faa]+1;fa[u][0]=faa;dfn[u]=++cntdfn;
		fir[u]=++cntt;st[0][cntt]=u;
		for(int i=1;i<=18;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(v==faa)continue;
			dfs(v,u);st[0][++cntt]=u;
		}
	}
	void prepare(){
//		lg[0]=-1;for(int i=1;i<=N*2;i++)lg[i]=lg[i>>1]+1;
//		for(int i=1;i<=17;i++){
//			for(int j=1;j+(1<<i)-1<=cntt;j++){
//				st[i][j]=dep[st[i-1][j]]<dep[st[i-1][j+(1<<(i-1))]]?st[i-1][j]:st[i-1][j+(1<<(i-1))];
//			}
//		}
	}
//	int Lca(int a,int b){
//		int l=fir[a],r=fir[b],k;
//		if(l>r)swap(l,r);
//		k=lg[r-l+1];
//		return dep[st[k][l]]<dep[st[k][r-(1<<k)+1]]?st[k][l]:st[k][r-(1<<k)+1];
//	}
	int Lca(int a,int b){
		if(dep[a]<dep[b])swap(a,b);
		for(int i=18;i>=0;i--)if(dep[fa[a][i]]>=dep[b])a=fa[a][i];
		if(a==b)return a;
		for(int i=18;i>=0;i--)if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
		return fa[a][0];
	}
}
using TREE::dfs;
using TREE::Lca;

using TREE::cm;
using TREE::cmm;
using TREE::dep;
using TREE::fa;
using TREE::dfn; 
namespace BLOCKS{
	int id[N];//关键点号码,判断是否是关键点 
	int sta[N],top;
	void build_fake(vector<int> &k){
		static int sta[N],top;
		static vector<int> ri;
		sort(k.begin(),k.end(),cmm);
		k.resize(unique(k.begin(),k.end())-k.begin());
		sta[++top]=k[0];ri.clear();ri.pb(k[0]);
		for(int i=1;i<k.size();i++){
			int lca=Lca(sta[top],k[i]);
			if(lca==k[i]){
				sta[++top]=k[i];
			}else{
				while(top&&dep[sta[top-1]]>=dep[lca])--top;
				if(sta[top]!=lca){
					ri.pb(lca);sta[top]=lca;
				}sta[++top]=k[i];
			}
			ri.pb(k[i]);
		}k=ri;
	} 
	void dfs1(int u,int faa){
		for(int i=0;i<3;i++) cur[a[u][i]]++;
		if(id[u]!=-1)
			for(int i=1;i<=n;i++)
				sum[id[u]][i]=cur[i];
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(v==faa)continue;
			dfs1(v,u);
		}
		for(int i=0;i<3;i++)--cur[a[u][i]];
	}
	void dfs(int u,int faa,int fi,int size,int color){
		for(int i=0;i<3;i++)cur[a[u][i]]++,\
		modify(size,color,cur[a[u][i]],a[u][i]);
		if(id[u]!=-1)Color[fi][id[u]]=color,Size[fi][id[u]]=size;
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(v==faa)continue;
			dfs(v,u,fi,size,color);
		}
		for(int i=0;i<3;i++)cur[a[u][i]]--;
	}
	void getup(int u,int faa,int tp){
		if(id[u]!=-1)tp=u;
		up[u]=tp;
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(v==faa)continue;getup(v,u,tp);
		}
	}
	void getdown(int u,int faa){
		if(id[u]!=-1)down[u]=u;else down[u]=-1;
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(v==faa)continue;
			getdown(v,u);
			if(down[u]==-1&&down[v]!=-1)down[u]=down[v];
		}
	}
	int query(int x,int y,int c){
		int u=id[x],v=id[y],f=LCA[u][v];
		return sum[u][c]+sum[v][c]-2*sum[f][c]+val[f][c];
	}
	int query(int u,int v){
		int lca=Lca(u,v),size=0,color=n+1;top=0;
//		cout<<lca<<'\n';
//		cout<<u<<" "<<v<<" "<<lca<<endl;
		if(up[u]==up[v]){
			while(u!=lca){
				for(int i=0;i<3;i++){
					++cur[a[u][i]],sta[++top]=a[u][i];
				}u=fa[u][0];
			}
			while(v!=lca){
				for(int i=0;i<3;i++){
					++cur[a[v][i]],sta[++top]=a[v][i];
				}v=fa[v][0];
			}
			for(int i=0;i<3;i++)++cur[a[u][i]],sta[++top]=a[u][i];
			for(int i=1;i<=top;i++){
				if(!vis[sta[i]]){
					vis[sta[i]]=1;
					modify(size,color,cur[sta[i]],sta[i]);
				}
			}
		}
		else{
			if(dep[up[u]]<dep[lca]||dep[up[v]]<dep[lca]){
				if(dep[up[v]]<dep[lca])swap(u,v);
				while(u!=lca){
					for(int i=0;i<3;i++){
						sta[++top]=a[u][i];cur[a[u][i]]++;
					}u=fa[u][0];
				}
				while(v!=up[v]){
					for(int i=0;i<3;i++){
						sta[++top]=a[v][i];cur[a[v][i]]++;
					}v=fa[v][0];
				}
				int gu=fa[down[u]][0];
				while(gu!=u){
					for(int i=0;i<3;i++){
						sta[++top]=a[gu][i];cur[a[gu][i]]++;
					}gu=fa[gu][0];
				}for(int i=0;i<3;i++){
					sta[++top]=a[u][i];cur[a[u][i]]++;
				}u=down[u];
			}else{
				while(u!=up[u]){
					for(int i=0;i<3;i++){
						sta[++top]=a[u][i];cur[a[u][i]]++;
					}u=fa[u][0];
				}
				while(v!=up[v]){
					for(int i=0;i<3;i++){
						sta[++top]=a[v][i];cur[a[v][i]]++;
					}v=fa[v][0];
				}
			}
			size=Size[id[u]][id[v]],color=Color[id[u]][id[v]];
			for(int i=1;i<=top;i++){
				if(!vis[sta[i]]){
					vis[sta[i]]=1;
					modify(size,color,cur[sta[i]]+query(u,v,sta[i]),sta[i]);
				}
			}
		}
		cout<<size<<" "<<color<<'\n';
		last^=size;last^=color;
		for(int i=1;i<=top;i++)
			vis[sta[i]]=0,cur[sta[i]]=0;
		
	}
	void prepare(){
		static int ID[N],DIST[N];//临时数组。 
		for(int i=1;i<=n;i++){
			ID[i]=i;DIST[i]=0;
		}sort(ID+1,ID+n+1,cm);
//		for(int i=233;i<=283;i++)cout<<ID[i]<<" ";cout<<'\n';
		for(int i=1;i<=n;i++){
			for(int j=first[ID[i]];j;j=nxt[j]){
				int v=to[j];if(v==fa[ID[i]][0])continue;
				DIST[ID[i]]=max(DIST[ID[i]],DIST[v]+1);
			}
			if(ID[i]==1||DIST[ID[i]]>=225){
				DIST[ID[i]]=0;key.pb(ID[i]);
			}
		}
//		cout<<key.size()<<'\n';
		build_fake(key);
//		cout<<key.size()<<'\n';
		memset(id,-1,sizeof(id));
		for(int i=0;i<key.size();i++){
			id[key[i]]=i;
			for(int j=0;j<3;j++){
				val[i][a[key[i]][j]]++; 
			}
		}
		for(int i=0;i<key.size();i++){
			for(int j=0;j<key.size();j++){
				LCA[i][j]=id[Lca(key[i],key[j])];
			}
		}
//		for(int i=1;i<=10;i++){
//			for(int j=1;j<=10;j++)cout<<LCA[i][j]<<" ";cout<<'\n';
//		}
		dfs1(1,0);//预处理每个关键点到根的颜色信息 
//		for(int i=1;i<=10;i++){
//			for(int j=1;j<=10;j++){
//				cout<<sum[i][j]<<" ";
//			}cout<<endl;
//		}
		for(int i=0;i<key.size();i++){//cout<<i<<" ";
			dfs(key[i],0,i,0,N+1);//起点号,父亲,关键点号,出现次数,颜色序号
		}
		getup(1,0,-1);//起点,父亲,top 
		getdown(1,0); //起点,父亲 
	}
}
signed main(){
	int size=100<<20;//40M
//    __asm__ ("movl  %0, %%esp\n"::"r"((char*)malloc(size)+size));//调试用这个 
    __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//提交用这个 
//	freopen("mode1.in","r",stdin);
//	freopen("1.out","w",stdout);
	Type=in;n=in;
	for(int i=1;i<=n;i++)for(int j=0;j<3;j++)a[i][j]=in;
	for(int x,y,i=1;i<n;i++){
		x=in;y=in;add(x,y);add(y,x);
	}
	TREE::dfs(1,0);TREE::prepare();
	BLOCKS::prepare();q=in;
//	for(int i=1;i<=50;i++)cout<<BLOCKS::id[i]<<" ";cout<<endl;
	while(q--){
		int u=in;int v=in;
		u=u^(last*Type),v=v^(last*Type);
		BLOCKS::query(u,v);//ed=clock();DD
	}exit(0);
	return 0;
} 

这里有一个没调试出来的主席树,,日

#include<bits/stdc++.h>
using namespace std;
#define in read()
#define pb push_back
int in{
	int cnt=0,f=1;char ch=0;
	while(!isdigit(ch)){
		ch=getchar();if(ch=='-')f=-1;
	}
	while(isdigit(ch)){
		cnt=cnt*10+ch-48;
		ch=getchar();
	}return cnt*f;
}
const int N=8e4+3,M=853;int top;
int Type,last,n,q,a[N][3],sta[N];
int Size[M][M],Color[M][M],up[N];
int first[N],nxt[N*2],to[N*2],tot;
int Lca[M][M],cur[N],vis[N];
int id[N];vector<int> key;
void add(int a,int b){
	nxt[++tot]=first[a];first[a]=tot;to[tot]=b;
}
void modify(int &SIZE,int &COLOR,int NSIZE,int NCOLOR){
	if(SIZE<=NSIZE){
		if(SIZE<NSIZE){
			SIZE=NSIZE;COLOR=NCOLOR;
		}else{
			if(COLOR>NCOLOR)COLOR=NCOLOR; 
		}
	}
}
namespace zxs{
	int L[N<<7],R[N<<7],size[N<<7],CNT;
	int rt[N];
	int build(int l,int r){
		int root=++CNT;
		int mid=(l+r)>>1;
		if(l<r){
			L[root]=build(l,mid);R[root]=build(mid+1,r);
		}return root;
	}
	int modify(int pre,int l,int r,int key){
		int root=++CNT;
		L[root]=L[pre],R[root]=R[pre],size[root]=size[pre]+1;
		if(l<r){
			int mid=(l+r)>>1;
			if(key<=mid)
			L[root]=modify(L[pre],l,mid,key);else R[root]=modify(R[pre],mid+1,r,key);
		}return root;
	}
	int query(int u,int v,int lca,int lcaa,int l,int r,int pos){
		if(l==r)return size[u]+size[v]-size[lca]-size[lcaa];
		int mid=(l+r)>>1;if(pos<=mid)return query(L[u],L[v],L[lca],L[lcaa],l,mid,pos);
		else return query(R[u],R[v],R[lca],R[lcaa],mid+1,r,pos);
	}
}
using zxs::build;
using zxs::query;
using zxs::rt;
namespace TREE{
	int fa[N][20],dep[N],dfn[N],dfncnt;
	bool cm(int a,int b){
		return dep[a]>dep[b];
	}
	bool cmm(int a,int b){
		return dfn[a]<dfn[b];
	}
	void dfs(int u,int faa){
		fa[u][0]=faa;dep[u]=dep[faa]+1;
		for(int i=1;i<=18;i++)fa[u][i]=fa[fa[u][i-1]][i-1];
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(v==faa)continue;
			dfs(v,u);
		}
	}
	
	int LCA(int a,int b){
		if(dep[a]<dep[b])swap(a,b);
		for(int i=18;i>=0;i--)if(dep[fa[a][i]]>=dep[b])a=fa[a][i];
		if(a==b)return a;
		for(int i=18;i>=0;i--)if(fa[a][i]!=fa[b][i])a=fa[a][i],b=fa[b][i];
		return fa[a][0];
	}
}
using TREE::fa;
using TREE::dep;
using TREE::dfn;
using TREE::LCA;
using TREE::cm;
using TREE::cmm;
int upp[N];
namespace BLOCKS{
	int gu=0;
	void dfs(int u,int faa,int fi,int size,int color){
		for(int i=0;i<3;i++)cur[a[u][i]]++,modify(size,color,cur[a[u][i]],a[u][i]);
		if(id[u]!=-1)Size[fi][id[u]]=size,Color[fi][id[u]]=color;
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(v==faa)continue;
			dfs(v,u,fi,size,color);
		}for(int i=0;i<3;i++)cur[a[u][i]]--;
	}
	void getup(int u,int faa,int tp){
		upp[u]=tp;
		if(id[u]!=-1)tp=u;
		up[u]=tp;
		for(int i=first[u];i;i=nxt[i]){
			int v=to[i];if(v==faa)continue;
			getup(v,u,tp); 
		}
	}
	void prepare(){
		static int ID[N],DIST[N];
		for(int i=1;i<=n;i++)ID[i]=i,DIST[i]=0;
		sort(ID+1,ID+n+1,cm);
		for(int i=1;i<=n;i++){
			int x=ID[i];
			for(int j=first[x];j;j=nxt[j]){
				int v=to[j];if(v==fa[x][0])continue;
				DIST[x]=max(DIST[x],DIST[v]+1);
			}
			if(ID[i]==1||DIST[x]>100){
				DIST[x]=0;key.pb(x);
			}
		}
		memset(id,-1,sizeof(id));
		for(int i=0;i<key.size();i++){
			id[key[i]]=i;
		}


		for(int i=0;i<key.size();i++){
			dfs(key[i],0,i,0,n+1);
		}getup(1,0,-1);
	}
	void query(int u,int v){
		int lca=LCA(u,v);top=0;int size=0,color=n+1;
		if(up[u]==up[v]){
			while(u!=lca){
				for(int i=0;i<3;i++){
					cur[a[u][i]]++;sta[++top]=a[u][i];
				}u=fa[u][0];
			}
			while(v!=lca){
				for(int i=0;i<3;i++){
					cur[a[v][i]]++;sta[++top]=a[v][i];
				}v=fa[v][0];
			}
			for(int i=0;i<3;i++)cur[a[v][i]]++,sta[++top]=a[v][i];
			for(int i=1;i<=top;i++){
				if(!vis[sta[i]]){
					vis[sta[i]]=1;modify(size,color,cur[sta[i]],sta[i]);
				}
			}
		}else{
			if(dep[up[u]]<dep[lca]||dep[up[v]]<dep[lca]){
				if(dep[up[v]]<dep[lca])swap(u,v);
				while(u!=lca){
					for(int i=0;i<3;i++)cur[a[u][i]]++,sta[++top]=a[u][i];
					u=fa[u][0];
				}
				while(v!=up[v]){
					for(int i=0;i<3;i++)cur[a[v][i]]++,sta[++top]=a[v][i];
					v=fa[v][0];
				}int p=v;
				while(dep[upp[p]]>=dep[lca]){p=upp[p];}int x=p;
				p=fa[p][0];
				while(p!=lca){
					for(int i=0;i<3;i++)cur[a[p][i]]++,sta[++top]=a[p][i];
					p=fa[p][0];
				}
				for(int i=0;i<3;i++)cur[a[u][i]]++,sta[++top]=a[u][i];
				u=x;
			}else{
				while(u!=up[u]){
					for(int i=0;i<3;i++)cur[a[u][i]]++,sta[++top]=a[u][i];
					u=fa[u][0];
				}
				while(v!=up[v]){
					for(int i=0;i<3;i++)cur[a[v][i]]++,sta[++top]=a[v][i];
					v=fa[v][0];
				}
			}
			size=Size[id[u]][id[v]],color=Color[id[u]][id[v]];
			for(int i=1;i<=top;i++){
				if(!vis[sta[i]]){
					vis[sta[i]]=1;
					modify(size,color,cur[sta[i]]+zxs::query(rt[u],rt[v],rt[lca],rt[fa[lca][0]],1,n,sta[i]),sta[i]);
				}
			}
		}
		last^=size;last^=color;
		cout<<size<<" "<<color<<'\n';
		for(int i=1;i<=top;i++){
			vis[sta[i]]=0;cur[sta[i]]=0;
		}
	}
}
void Dfs(int u,int faa){
	rt[u]=zxs::modify(rt[faa],1,n,a[u][0]);
	rt[u]=zxs::modify(rt[u],1,n,a[u][1]);
	rt[u]=zxs::modify(rt[u],1,n,a[u][2]);
	for(int i=first[u];i;i=nxt[i]){
		int v=to[i];if(v==faa)continue;
		Dfs(v,u);
	}
}
signed main(){
		int size=100<<20;//40M
    __asm__ ("movl  %0, %%esp\n"::"r"((char*)malloc(size)+size));//调试用这个 
//    __asm__ ("movq %0,%%rsp\n"::"r"((char*)malloc(size)+size));//提交用这个 
	freopen("mode1.in","r",stdin);
//	freopen("1.out","w",stdout);
	Type=in;n=in;
	for(int i=1;i<=n;i++)for(int j=0;j<3;j++)a[i][j]=in;
	for(int i=1;i<n;i++){int x=in;int y=in;add(x,y);add(y,x);}
	rt[0]=build(1,n);
	Dfs(1,0);
	TREE::dfs(1,0);BLOCKS::prepare();
	q=in;
	while(q--){
		int x=in;int y=in;
		x^=(last*Type),y^=(last*Type);
		BLOCKS::query(x,y);
	}exit(0);
	return 0;
} 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值