题目的意思是给你一颗树n(100000)个树的几点,然后开始树都是白色的,根的颜色是红色的,然后给你m个操作,1 x操作表示把x这个点变成红色,2 x询问x到最近红色点的距离,我听闻有3种解法(分割+点的分治+轻重边)
长度,780ms ac这个好像是官方提供的解
解法1 对于m(100000)个询问分成sqrt(m) 块,然后在每个块内,如果是更改操作,把相应点放入临时数组,对于查询,先看原图最小距离,和临时数组里面点的最小值(通过lca 处理)对于每个块之间用用一次bfs 把临时数组里面的值更新给原图,可以得出负责度为(sqrt(m)*n)开始写的时候无限tle 后面只对于更改分块,因为就更改会改变临时数组的
#include<cstdio>
#include<cmath>
#include<cstring>
#include<iostream>
#define M 101000
#define inf 0x3f3f3f3f
using namespace std;
struct G{
int head[M],en;
struct E{
int u,v,next;
}e[M<<2];
void init(){
memset(head,-1,sizeof(head));en=0;
}
void add(int u,int v){
e[en].u=u;e[en].v=v;e[en].next=head[u];head[u]=en++;
}
}g1;
int dex[M*2];
void init_dex(){
dex[0]=-1;
for(int i=1;i<M*2-1;i++){
if(i&(i-1)) dex[i]=dex[i-1];
else dex[i]=dex[i-1]+1;
}
}
int aa[M*2],bb[M*2],en;
struct R{
int head[M*2],raa[M*2][20],rbb[M*2][20];
void init(){
memset(rbb,inf,sizeof(rbb));
memset(head,-1,sizeof(head));
for(int i=0;i<en;i++){
int u=aa[i];
if(head[u]==-1){
head[u]=i;
}
raa[i][0]=aa[i];
rbb[i][0]=bb[i];
}
for(int i=1;(1<<i)<=en;i++){
for(int j=0;j+(1<<i)<en;j++){
int next=j+(1<<(i-1));
if(rbb[j][i-1]<rbb[next][i-1]){
rbb[j][i]=rbb[j][i-1];
raa[j][i]=raa[j][i-1];
}
else{
rbb[j][i]=rbb[next][i-1];
raa[j][i]=raa[next][i-1];
}
}
}
}
int query(int l,int r){
l=head[l];r=head[r];
if(l>r) swap(l,r);
int p1=dex[r-l+1];
r-=(1<<(p1))-1;
if(rbb[l][p1]<=rbb[r][p1]) return raa[l][p1];
return raa[r][p1];
}
}rmq;
int dis[M];
int is_red[M];
void dfs1(int u,int p,int level){
dis[u]=level;
aa[en]=u;
bb[en++]=level;
for(int i=g1.head[u];~i;i=g1.e[i].next){
int v=g1.e[i].v;
if(v==p) continue;
dfs1(v,u,level+1);
aa[en]=u;
bb[en++]=level;
}
}
int block[M];
int tmin[M];
int my_queue[M],qh,qt;
void dfs2(int u,int p,int level){
if(tmin[u]>level) tmin[u]=level;
else return ;
for(int i=g1.head[u];~i;i=g1.e[i].next){
int v=g1.e[i].v;
if(v==p) continue;
if(is_red[v]) continue;
dfs2(v,u,level+1);
}
}
void bfs(){
while(qt>=qh){
int u=my_queue[qh++];
if(is_red[u]==1) tmin[u]=0;
for(int i=g1.head[u];~i;i=g1.e[i].next){
int v=g1.e[i].v;
if(tmin[v]>tmin[u]+1){
tmin[v]=tmin[u]+1;
my_queue[++qt]=v;
}
}
}
}
int main(){
init_dex();
int n,m;while(~scanf("%d%d",&n,&m)){
g1.init();
for(int i=0;i<n-1;i++){
int u,v;scanf("%d%d",&u,&v);
g1.add(u,v);g1.add(v,u);
}
en=0;
dfs1(1,-1,0);
rmq.init();
for(int i=1;i<=n;i++){
tmin[i]=dis[i];
}
int num=0;
int flag=0;
int siz=200;
memset(is_red,0,sizeof(is_red));
is_red[1]=1;
for(int i=0;i<m;i++){
int t1,t2;scanf("%d%d",&t1,&t2);
if(t1==2){
if(is_red[t2]){
puts("0");continue;
}
int ans=tmin[t2];
for(int j=0;j<num;j++){
int tt=block[j];
int fa=rmq.query(t2,tt);
int t3=dis[t2]+dis[tt]-2*dis[fa];
if(t3<ans) ans=t3;
}
printf("%d\n",ans);
}
else{
flag++;
is_red[t2]=1;
block[num++]=t2;
}
if(flag==siz){
qh=0;qt=-1;
for(int j=0;j<num;j++){
int t3=block[j];
my_queue[++qt]=t3;
}
bfs();
flag=0;
num=0;
}
}
}
return 0;
}
长度,780ms ac这个好像是官方提供的解
解法2 树点的分治 大神的思路自己模仿代码
#include<cstdio>
#include<cstring>
#include<iostream>
#define M 111000
#define inf 0x3f3f3f3f
using namespace std;
struct G1{
int head[M],en;
struct E{
int u,v,next,flag;
}e[M<<4];
void init(){
memset(head,-1,sizeof(head));en=0;
}
void add(int u,int v){
e[en].flag=0;
e[en].u=u;e[en].v=v;e[en].next=head[u];head[u]=en++;
}
}g1;
struct G2{
int head[M],en;
struct E{
int u,v,next,cost;
}e[M<<6];
void init(){
memset(head,-1,sizeof(head));en=0;
}
void add(int u,int v,int cost){
e[en].cost=cost;
e[en].u=u;e[en].v=v;e[en].next=head[u];head[u]=en++;
}
}g2;
int dis[M],cen,ms[M],son[M],siz;
void find_root(int u,int p){
son[u]=1,ms[u]=0;
for(int i=g1.head[u];~i;i=g1.e[i].next){
int v=g1.e[i].v;
if(v==p||g1.e[i].flag) continue;
find_root(v,u);
son[u]+=son[v];
if(son[v]>ms[u]) ms[u]=son[v];
}
if(ms[u]<siz-son[u]) ms[u]=siz-son[u];
if(ms[u]<ms[cen]){
cen=u;
}
}
void dfs(int u,int p,int pos){
dis[u]=dis[p]+1;
g2.add(u,pos,dis[u]);
for(int i=g1.head[u];~i;i=g1.e[i].next){
int v=g1.e[i].v;
if(g1.e[i].flag||v==p) continue;
dfs(v,u,pos);
}
}
void divide(int pos){
dis[0]=-1;
dfs(pos,0,pos);
for(int i=g1.head[pos];i!=-1;i=g1.e[i].next){
g1.e[i^1].flag=1;
if(g1.e[i].flag) continue;
int v=g1.e[i].v;
cen=0;ms[cen]=siz=son[v];
find_root(v,-1);
divide(cen);
}
}
int ans[M];
void mark(int u){
ans[u]=0;
for(int i=g2.head[u];~i;i=g2.e[i].next){
int v=g2.e[i].v;
int cost=g2.e[i].cost;
if(ans[v]>ans[u]+cost) ans[v]=ans[u]+cost;
}
}
int query(int u){
int ret=ans[u];
for(int i=g2.head[u];~i;i=g2.e[i].next){
int v=g2.e[i].v;
int cost=g2.e[i].cost;
if(ret>ans[v]+cost) ret=ans[v]+cost;
}
return ret;
}
int main(){
int n,m;while(~scanf("%d%d",&n,&m)){
g1.init();
for(int i=0;i<n-1;i++){
int u,v;scanf("%d%d",&u,&v);g1.add(u,v);g1.add(v,u);
}
siz=n;cen=0;ms[cen]=siz;
find_root(1,-1);
g2.init();
divide(cen);
memset(ans,inf,sizeof(ans));
mark(1);
for(int i=0;i<m;i++){
int t1,t2;scanf("%d%d",&t1,&t2);
if(t1==1){
mark(t2);
}
else{
int tt=query(t2);
printf("%d\n",tt);
}
}
}
return 0;
}