继紫荆花之恋后第二道蒟蒻所知道的会动的树的点分治
题意:给你一颗未知的树,你只知道1,你可以询问explore(u,v),得到(u,v)路径上的第一个点,请你在有限的询问次数内确定这一棵树
首先随机化一下访问次数,这样就不会被奇奇怪怪地卡掉了(虽然出题人也是随的数据)
①:链,询问次数限制n+logn,记录链的两端,一端不对跳到另一端,期望出错次数logn
②:树,询问次数限制nlogn
我们可以每次跳到explore得到的点所属的下一层重心,这样每次少去一半的点,就可以保证询问次数是nlogn了
所以现在考虑的就是怎么维护动态的重心,所以大概按照紫荆花之恋的做法就 ok o k 了
但其实有两种写法,
第一种
就是每次找到一个新的点就看看树是否平衡(这样就和紫荆花之恋一模一样了)
第二种
就是把那条未访问的链一次性走到底,然后再去重构点分树
这里说一下第二种做法
后面一直在考虑,怎么维护这个点所属的下一层重心??
参考了别人的代码后发现可以用 map m a p 存一下 G[u][v] G [ u ] [ v ] ,表示 u u 所属的重心走到后所属的下一层重心
然后我想到重构的时候怎么去dfs清空这棵树?
然后发现可以用 auto. a u t o . ….. c++11 c + + 11 真是神奇,这样的话就是最后拉一条链出来后再chk就好了
然后实际上第二种要快得多(其实想想也知道)
#include<bits/stdc++.h>
#include"rts.h"
#define fp(i,a,b) for(int i=a,I=b+1;i<I;++i)
#define fd(i,a,b) for(int i=a,I=b-1;i>I;--i)
#define go(i,u) for(int i=fi[u],v=e[i].to;i;v=e[i=e[i].nx].to)
#define get explore
#define pb push_back
using namespace std;
template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
template<class T>inline bool cmin(T&a,const T&b){return a>b?a=b,1:0;}
const int N=3e5+5;
const double alpha=0.777;
typedef int arr[N];
struct eg{int nx,to;}e[N<<1];
int n,ce,rt,Rt,Sum;arr sz,fx,Fa,Fr,fi,Dsz;bool vis[N];
vector<int>id,New,S;
map<int,int>G[N];
inline void add(int u,int v){e[++ce]=eg{fi[u],v},fi[u]=ce;}
inline void adc(int fa,int rt,int in){Fa[rt]=fa,G[fa][in]=rt,Fr[rt]=in;}
void gr(int u,int fa){
fx[u]=0,sz[u]=1;
go(i,u)if(!vis[v]&&v^fa)gr(v,u),sz[u]+=sz[v],cmax(fx[u],sz[v]);
cmax(fx[u],Sum-sz[u]);if(fx[u]<fx[rt])rt=u;
}
void sol(int u){
Dsz[u]=vis[u]=1;int s;
go(i,u)if(!vis[v])Sum=sz[v],gr(v,rt=0),sol(s=rt),adc(Fa[s]=u,s,v),Dsz[u]+=Dsz[s];
}
void clr(int u){vis[u]=0;for(auto i:G[u])clr(i.second);G[u].clear();}
inline void Re(int u){
clr(u);Sum=Dsz[u];gr(u,rt=0);
if(u==Rt)Fa[Rt=rt]=0;else adc(Fa[u],rt,Fr[u]);sol(rt);
}
inline void find(int x){
int u=Rt,v;New.clear(),S.clear();
while(u^x){
v=get(u,x);
if(!vis[v])add(u,v),add(v,u),adc(u,v,v),vis[v]=1,New.pb(v);
S.pb(u=G[u][v]);
}
for(int i:S)Dsz[Fa[i]]-=Dsz[i];for(int i:New)Dsz[i]=1;
for_each(S.rbegin(),S.rend(),[](int i){Dsz[Fa[i]]+=Dsz[i];});
for(int i:S)if(Dsz[i]>Dsz[Fa[i]]*alpha)return Re(Fa[i]);
}
inline void chain(){
int L=1,R=1;
for(int i:id)if(!vis[i]){
int x=get(L,i);
if(vis[x])x=R,R=i;
else L=i,vis[x]=1;
while(x!=i)vis[x=get(x,i)]=1;
}
}
void play(int _,int,int ty){
n=_;Rt=vis[1]=1;fx[0]=N;fp(i,2,n)id.pb(i);
srand(time(0)),random_shuffle(id.begin(),id.end());
if(ty==3)return chain();
for(int i:id)if(!vis[i])find(i);
}