省选模拟赛20200417 B、树 (点分治+ST表 || 线段树分治+虚树)

省选模拟赛20200417 B、树 (点分治+ST表 || 线段树分治+虚树)_第1张图片

省选模拟赛20200417 B、树 (点分治+ST表 || 线段树分治+虚树)_第2张图片

省选模拟赛20200417 B、树 (点分治+ST表 || 线段树分治+虚树)_第3张图片

 

 

题解

一看就不会

写了个60分的暴力就走人

最后两分钟想到一个假的正解:换根维护线段树

20200418:从早上9:00写到10:30,发现是有问题的

因为换根时的修改区间在dfs序上,是连续的

但是查询的区间只是编号连续,在dfs序上不一定连续。。。

所以就只有看题解了

题解:

省选模拟赛20200417 B、树 (点分治+ST表 || 线段树分治+虚树)_第4张图片

省选模拟赛20200417 B、树 (点分治+ST表 || 线段树分治+虚树)_第5张图片

哦,原来还有这种操作,对编号分块,对编号建线段树

好难写啊

看了一下std

4KB

读不下去了

看了一下Master.Yi大佬的代码

2KB

就看他的了

 

大概阅读了5min

哦哦哦,这不就是点分治套ST表吗

对每一个点分中心维护一个ST表,记录当前点分区域每个点到点分中心的距离

然后把这个点分区域的所有询问直接利用ST表查询

 

虽然一次查询,有些点不一定可以查询到最有解,但是最后一定是可以找到最优解的

代码:

#include
#include
#include
#include
using namespace std;
inline int gi()
{
	char c;int num=0,flg=1;
	while((c=getchar())<'0'||c>'9')if(c=='-')flg=-1;
	while(c>='0'&&c<='9'){num=num*10+c-48;c=getchar();}
	return num*flg;
}
#define N 100005
#define LOG 18
int n,m,siz[N],stk[N],top,dis[N],st[N][LOG+2],lg[N],ans[N];
bool vis[N];
int fir[N],nxt[N<<1],to[N<<1],cd[N<<1],tot;
inline void adde(int x,int y,int z)
{
	to[++tot]=y;nxt[tot]=fir[x];fir[x]=tot;cd[tot]=z;
}
struct node{int id,l,r;};
vector Q[N];
void getroot(int u,int ff,int all,int &g)
{
	siz[u]=1;bool flg=1;
	for(int p=fir[u],v;p;p=nxt[p]){
		v=to[p];
		if(!vis[v]&&v!=ff){
			getroot(v,u,all,g);
			siz[u]+=siz[v];
			flg&=((siz[v]<<1)<=all);
		}
	}
	if(flg&&((all-siz[u])<<1)<=all)
		g=u;
}
void dfs(int u,int ff)
{
	stk[++top]=u;
	for(int v,p=fir[u];p;p=nxt[p]){
		v=to[p];
		if(!vis[v]&&v!=ff){
			dis[v]=dis[u]+cd[p];
			dfs(v,u);
		}
	}
}
inline int query(int x,int y)
{
	int k=lg[y-x+1];
	return min(st[x][k],st[y-(1<>1]+1;st[i][0]=dis[stk[i]];}
	for(j=1;j<=lg[top];j++)
		for(i=1,l=1<>1)][j-1]);
	for(int i=1,l,r;i<=top;i++)
		for(int j=0,x=stk[i],lim=Q[x].size();j

 

 

std:

#include
#include
#include
#include
#include
using namespace std;

#define INF 1<<29

#define N 100010
int n,bel[17][N],Root[17][N];
int head[N],next[N<<1],end[N<<1],len[N<<1];
inline void addedge(int a,int b,int l){
	static int q=1;
	end[q]=b;
	next[q]=head[a];
	head[a]=q;
	len[q++]=l;
}
inline void make(int a,int b,int l){
	addedge(a,b,l);
	addedge(b,a,l);
}

#define l(x) S[x].l
#define r(x) S[x].r
struct Node{
	int l,r,re;
}S[15000010];
int cnt;

inline void Insert(int&q,int tl,int tr,int ins,int d){
	if(!q){
		q=++cnt;
		S[q].re=d;
	}
	S[q].re=min(S[q].re,d);
	if(tl==tr)
		return;
	int mid=(tl+tr)>>1;
	if(ins<=mid)
		Insert(S[q].l,tl,mid,ins,d);
	else
		Insert(S[q].r,mid+1,tr,ins,d);
}
inline int Query(int q,int tl,int tr,int dl,int dr){
	if(!q)
		return INF;
	if(dl<=tl&&tr<=dr)
		return S[q].re;
	int mid=(tl+tr)>>1;
	if(dr<=mid)
		return Query(S[q].l,tl,mid,dl,dr);
	else if(dl>mid)
		return Query(S[q].r,mid+1,tr,dl,dr);
	else
		return min(Query(S[q].l,tl,mid,dl,mid),Query(S[q].r,mid+1,tr,mid+1,dr));
}

int q[N],fr,ta;
struct Array{
	int re[N],t[N],tclock,init;
	Array():tclock(0),init(0){}
	inline int operator[](const int&x){
		if(t[x]!=tclock)
			t[x]=tclock,re[x]=init;
		return re[x];
	}
	inline void modify(int x,int c){
		t[x]=tclock;
		re[x]=c;
	}
}pa;
int seq[N],id;
int size[N],dis[17][N];
bool ban[N];

inline void solve(int x,int dep){
	int i,j;
	fr=ta=0;
	q[ta++]=x;
	id=0,seq[++id]=x;
	++pa.tclock;
	while(fr^ta){
		i=q[fr++];
		for(j=head[i];j;j=next[j]){
			if(pa[i]!=end[j]&&!ban[end[j]]){
				pa.modify(end[j],i);
				q[ta++]=seq[++id]=end[j];
			}
		}
	}
	int Maxsize,real_Root;
	for(i=id;i>=1;--i){
		size[seq[i]]=1;
		for(j=head[seq[i]];j;j=next[j]){
			if(end[j]!=pa[seq[i]]&&!ban[end[j]])
				size[seq[i]]+=size[end[j]];
		}
	}
	
	if(size[x]==1){
		bel[dep][x]=x;
		Insert(Root[dep][x],1,n,x,0);
		return;
	}
	
	for(i=1;i<=id;++i){
		Maxsize=size[x]-size[seq[i]];
		for(j=head[seq[i]];j;j=next[j]){
			if(end[j]!=pa[seq[i]]&&!ban[end[j]])
				Maxsize=max(Maxsize,size[end[j]]);
		}
		if(Maxsize<=size[x]/2)
			real_Root=seq[i];
	}
	
	fr=ta=0;
	q[ta++]=real_Root;
	++pa.tclock;
	dis[dep][real_Root]=0;
	bel[dep][real_Root]=real_Root;
	Insert(Root[dep][real_Root],1,n,real_Root,0);
	while(fr^ta){
		i=q[fr++];
		for(j=head[i];j;j=next[j]){
			if(end[j]!=pa[i]&&!ban[end[j]]){
				pa.modify(end[j],i);
				dis[dep][end[j]]=dis[dep][i]+len[j];
				bel[dep][end[j]]=real_Root;
				Insert(Root[dep][real_Root],1,n,end[j],dis[dep][end[j]]);
				q[ta++]=end[j];
			}
		}
	}
	
	ban[real_Root]=1;
	for(j=head[real_Root];j;j=next[j])
		if(!ban[end[j]])
			solve(end[j],dep+1);
}

int main(){
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	
	scanf("%d",&n);
	register int i;
	int a,b,c;
	for(i=1;i

 

 

 

 

 

 

 

 

 

 

 

 

 

你可能感兴趣的:(数据结构,分治,c++,算法,分治,数据结构)