zoukankan      html  css  js  c++  java
  • LOJ#6463 AK YOI 树分治+线段树合并

    传送门

    既然是树上路径统计问题,不难想到要使用树分治,这里以点分治为例

    由点分治的性质,每层只需要考虑经过重心的路径

    因为需要维护路径长度在一定范围内的最大权值和,所以要用一个数据结构维护一下到根节点距离在一定范围内的最大权值和

    显然线段树是一个不错的选择,对每个子树建立一个线段树,根节点的答案用每个子树的线段树都更新一遍即可

    考虑更新子树中的点的答案,这时需要使用除这棵子树外的所有子树的线段树一起更新

    我们可以使用线段树合并来维护,给子树任意确定一个顺序,然后通过维护每个子树的前缀和后缀线段树的并即可快速得到除去某棵子树后的线段树

    显然复杂度是有保证的,因为线段树合并的复杂度无论如何都不会高于暴力插入三遍

    总复杂度(O(nlog^2 n)),常数应该不小,不过跑的挺快233333

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=100005,maxm=maxn*100;
    const long long INF=0x5f5f5f5f5f5f5f5fll;
    void solve(int,int);
    int getcenter(int,int);
    int getdis(int);
    void getans(int,int);
    void modify(int,int,int&);
    int merge(int,int);
    long long query(int,int,int);
    long long mx[maxm];
    int lc[maxm],rc[maxm],cnt=0,root[maxn],prefix[maxn],suffix[maxn];
    vector<int>G[maxn];
    bool vis[maxn];
    long long w[maxn],ans[maxn],ant[maxn],tmp;
    int p[maxn],size[maxn],son[maxn],q[maxn],d[maxn],pr[maxn],nx[maxn];
    int n,m,L,R,val[maxn],s,t;
    int main(){
    	mx[0]=-INF;
    	scanf("%d%d%d",&n,&L,&R);
    	for(int i=1;i<=n;i++){
    		scanf("%d",&val[i]);
    		ans[i]=-3472328296227680305ll;
    	}
    	for(int i=1,x,y;i<n;i++){
    		scanf("%d%d",&x,&y);
    		G[x].push_back(y);
    		G[y].push_back(x);
    	}
    	solve(1,n);
    	for(int i=1;i<=n;i++){
    		if(i>1)printf(" ");
    		printf("%lld",ans[i]);
    	}
    	printf("
    ");
    	return 0;
    }
    void solve(int x,int sz){
    	x=getcenter(x,sz);
    	m=sz;
    	vis[x]=true;
    	w[x]=val[x];
    	d[x]=0;
    	if(sz==1)return;
    	s=0;
    	tmp=w[x];
    	modify(0,m,root[x]);
    	for(int i=0;i<(int)G[x].size();i++)
    		if(!vis[G[x][i]]){
    			p[G[x][i]]=x;
    			getdis(G[x][i]);
    		}
    	s=L;t=R;
    	for(int i=0,last=0;i<(int)G[x].size();i++)
    		if(!vis[G[x][i]]){
    			if(s<=m)ans[x]=max(ans[x],query(0,m,root[G[x][i]]));
    			prefix[G[x][i]]=merge(prefix[last],root[G[x][i]]);
    			pr[G[x][i]]=last;
    			last=G[x][i];
    		}
    	ant[x]=-INF;
    	for(int i=(int)G[x].size()-1,last=0;~i;i--)
    		if(!vis[G[x][i]]){
    			suffix[G[x][i]]=merge(suffix[last],root[G[x][i]]);
    			nx[G[x][i]]=last;
    			last=G[x][i];
    		}
    	for(int i=0;i<(int)G[x].size();i++)
    		if(!vis[G[x][i]])getans(G[x][i],val[x]);
    	ans[x]=max(ans[x],ant[x]);
    	root[x]=0;
    	for(int i=0;i<(int)G[x].size();i++)
    		if(!vis[G[x][i]]){
    			pr[G[x][i]]=nx[G[x][i]]=0;
    			root[G[x][i]]=prefix[G[x][i]]=suffix[G[x][i]]=0;
    		}
    	cnt=0;
    	for(int i=0;i<(int)G[x].size();i++)
    		if(!vis[G[x][i]])solve(G[x][i],size[G[x][i]]);
    }
    int getcenter(int x,int s){
    	int head=0,tail=0;
    	q[tail++]=x;
    	while(head!=tail){
    		x=q[head++];
    		size[x]=1;
    		son[x]=0;
    		for(int i=0;i<(int)G[x].size();i++)
    			if(!vis[G[x][i]]&&G[x][i]!=p[x]){
    				p[G[x][i]]=x;
    				q[tail++]=G[x][i];
    			}
    	}
    	for(int i=tail-1;i;i--){
    		x=q[i];
    		size[p[x]]+=size[x];
    		if(size[x]>size[son[p[x]]])son[p[x]]=x;
    	}
    	x=q[0];
    	while(son[x]&&size[son[x]]>(s>>1))x=son[x];
    	return x;
    }
    int getdis(int x){
    	int head=0,tail=0,rt=x;
    	q[tail++]=x;
    	while(head!=tail){
    		x=q[head++];
    		s=d[x]=d[p[x]]+1;
    		tmp=w[x]=w[p[x]]+val[x];
    		modify(0,m,root[rt]);
    		size[x]=1;
    		for(int i=0;i<(int)G[x].size();i++)
    			if(!vis[G[x][i]]&&G[x][i]!=p[x]){
    				p[G[x][i]]=x;
    				q[tail++]=G[x][i];
    			}
    	}
    	for(int i=tail-1;i;i--){
    		x=q[i];
    		size[p[x]]+=size[x];
    	}
    	return d[q[tail-1]];
    }
    void getans(int x,int v){
    	int head=0,tail=0,rt=merge(prefix[pr[x]],suffix[nx[x]]);
    	q[tail++]=x;
    	while(head!=tail){
    		x=q[head++];
     		s=L-d[x];
    		t=R-d[x];
    		if(t<0||s>m)ant[x]=-INF;
    		else ant[x]=w[x]-v+query(0,m,rt);
    		if(s<=0&&t>=0)ant[x]=max(ant[x],w[x]);
    		for(int i=0;i<(int)G[x].size();i++)
    			if(!vis[G[x][i]]&&G[x][i]!=p[x]){
    				p[G[x][i]]=x;
    				q[tail++]=G[x][i];
    			}
    	}
    	for(int i=tail-1;~i;i--){
    		x=q[i];
    		ant[p[x]]=max(ant[p[x]],ant[x]);
    		ans[x]=max(ans[x],ant[x]);
    	}
    }
    void modify(int l,int r,int &rt){
    	if(!rt){
    		rt=++cnt;
    		mx[rt]=-INF;
    		lc[rt]=rc[rt]=0;
    	}
    	mx[rt]=max(mx[rt],tmp);
    	if(l==r)return;
    	int mid=(l+r)>>1;
    	if(s<=mid)modify(l,mid,lc[rt]);
    	else modify(mid+1,r,rc[rt]);
    }
    int merge(int x,int y){
    	if(!x||!y)return x|y;
    	int z=++cnt;
    	mx[z]=max(mx[x],mx[y]);
    	lc[z]=merge(lc[x],lc[y]);
    	rc[z]=merge(rc[x],rc[y]);
    	return z;
    }
    long long query(int l,int r,int rt){
    	if(s<=l&&t>=r)return mx[rt];
    	int mid=(l+r)>>1;
    	if(t<=mid)return query(l,mid,lc[rt]);
    	if(s>mid)return query(mid+1,r,rc[rt]);
    	return max(query(l,mid,lc[rt]),query(mid+1,r,rc[rt]));
    }
    
  • 相关阅读:
    活动安排问题
    喵哈哈村的魔法考试 Round #5 (Div.2) C
    梯度下降,牛顿法 ,高斯牛顿法
    SSD模型解析
    训练较深的卷积神经网络时遇到的问题
    手写体识别
    Fast Patch-based Style Transfer of Arbitrary Style 理解
    多任务学习
    迁移学习(训练数据少的可怜时的办法)
    通过训练得出的结果修改模型
  • 原文地址:https://www.cnblogs.com/hzoier/p/9383245.html
Copyright © 2011-2022 走看看