题解

一看就不会

写了个60分的暴力就走人

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

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

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

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

所以就只有看题解了

题解:

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

好难写啊

看了一下std

4KB

读不下去了

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

2KB

就看他的了

 

大概阅读了5min

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

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

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

 

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

代码:

#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
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<node> 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<<k)+1][k]);
}
void solve(int u)
{
	dis[u]=top=0;
	dfs(u,0);
	sort(stk+1,stk+1+top);
	int i,j,l;lg[0]=-1;
	for(i=1;i<=top;i++){lg[i]=lg[i>>1]+1;st[i][0]=dis[stk[i]];}
	for(j=1;j<=lg[top];j++)
		for(i=1,l=1<<j;i+l-1<=top;i++)
			st[i][j]=min(st[i][j-1],st[i+(l>>1)][j-1]);
	for(int i=1,l,r;i<=top;i++)
		for(int j=0,x=stk[i],lim=Q[x].size();j<lim;j++){
			l=lower_bound(stk+1,stk+1+top,Q[x][j].l)-stk;
			r=upper_bound(stk+1,stk+1+top,Q[x][j].r)-stk-1;
			if(l<=r)ans[Q[x][j].id]=min(ans[Q[x][j].id],dis[x]+query(l,r));
		}
}
void TDC(int u,int all)
{
	getroot(u,0,all,u);vis[u]=1;
	solve(u);
	for(int i=fir[u],v;i;i=nxt[i])
		if(!vis[v=to[i]])
			TDC(v,siz[v]<siz[u]?siz[v]:all-siz[u]);
}
int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	int i,x,y,z,l,r;
	n=gi();
	for(i=1;i<n;i++){
		x=gi();y=gi();z=gi();
		adde(x,y,z);adde(y,x,z);
	}
	m=gi();
	for(i=1;i<=m;i++){
		l=gi();r=gi();x=gi();
		if(l<=x&&x<=r)
			ans[i]=0;
		else{
			Q[x].push_back((node){i,l,r});
			ans[i]=0x3f3f3f3f;
		}
	}
	TDC(1,n);
	for(i=1;i<=m;i++)
		printf("%d\n",ans[i]);
}

 

 

std:

#include<cstdio>
#include<cstring>
#include<cctype>
#include<iostream>
#include<algorithm>
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<n;++i)
		scanf("%d%d%d",&a,&b,&c),make(a,b,c);
	
	solve(1,0);
	
	int q;
	scanf("%d",&q);
	int l,r,x,re;
	while(q--){
		scanf("%d%d%d",&l,&r,&x);
		re=INF;
		for(i=0;i<17;++i){
			if(bel[i][x])
				re=min(re,dis[i][x]+Query(Root[i][bel[i][x]],1,n,l,r));
		}
		printf("%d\n",re);
	}
	
	fclose(stdin);
	fclose(stdout);
	return 0;
}