两种做法,一种是树分块+虚树,一种是树分块+主席树
我使用树分块+虚树,感觉好写一点qwq
预处理:
随机个关键点(当然是保证两两距离在
左右),然后把关键点的lca也点成关键点。即分块。
求出每个点向上走第一个关键点,每个点子树中(包括自己)第一个关键点,每个关键点到根路径上的颜色信息和(),任意两个关键点路径上的众数和次数(
)。
有性质:如果一个点不是关键点,则其子树中最多只有一个子树有关键点。(否则它会成为一个lca)
对于分块,我们从叶子节点开始,一旦走出dis>,则将当前点设为关键点。
然后虚树的建立方式找lca。
从每个关键点dfs一遍整棵树(),找出两两关键点的答案。
找向上走第一个关键点就像树链剖分第二个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;
}