• loj #2179. 「BJOI2017」树的难题 点分治+线段树


    对于树上统计路径的问题我们通常要用到点分治来搞一搞。

    首先我们点分治。

    摄当前的分治中心是 x,那么把 x 周围的点按照颜色排个序。

    统计的时候我们建两颗线段树,设当前处理到的 x 周围的点是 y,x 和 y 之间的点的颜色是 z ,那么第一颗线段树是 z 之前的颜色(不包括z),第二课线段树是 z。

    每棵线段树以到 x 距离为下表,存的是到 x 这段路程的权值。

    那么新统计到一个点的时候,在第一棵线段树我们直接加,第二课线段树加的时候减去拼接时候的损失。

    时间复杂度 (O(nlog^2n))

    细节较多。

    #include<algorithm>
    #include<iostream>
    #include<cstdio>
    #include<vector>
    #define lson (k<<1)
    #define rson ((k<<1)|1)
    using namespace std;
    int n,m,l,r,tot;
    const int N=200010,inf=2e9;
    int c[N];
    struct bian
    {
    	int to,c;
    	friend bool operator <(const bian &a,const bian &b){return a.c<b.c;}
    };
    vector<bian>v[N];
    inline int read()
    {
        int res = 0; char ch = getchar(); bool XX = false;
        for (; !isdigit(ch); ch = getchar())(ch == '-') && (XX = true);
        for (; isdigit(ch); ch = getchar())res = (res << 3) + (res << 1) + (ch ^ 48);
        return XX ? -res : res;
    }
    namespace solve1
    {
    	int ans=-2e9;
    	void dfs(int x,int fa,int dep,int sum,int last)
    	{
    		if(l<=dep&&dep<=r)ans=max(ans,sum);
    		if(dep>r)return;
    		for(int i=0,Siz=v[x].size();i<Siz;++i)
    			if(v[x][i].to!=fa)dfs(v[x][i].to,x,dep+1,sum+(v[x][i].c==last?0:c[v[x][i].c]),v[x][i].c);
    	}
    	void work()
    	{
    		for(int i=1;i<=n;++i)dfs(i,0,0,0,0);
    		cout<<ans;
    	}
    }
    struct XDS
    {
    	int tr[N<<2];
    	void pushup(int k)
    	{
    		tr[k]=max(tr[lson],tr[rson]);
    	}
    	void build(int k,int l,int r)
    	{
    		if(l==r)
    		{
    			tr[k]=-inf;
    			return;
    		}
    		int mid=(l+r)>>1;
    		build(lson,l,mid);build(rson,mid+1,r);
    		pushup(k);
    	}
    	void change(int k,int l,int r,int pos,int val)
    	{
    		if(l==r)
    		{
    			tr[k]=max(tr[k],val);
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(pos<=mid)change(lson,l,mid,pos,val);
    		else change(rson,mid+1,r,pos,val);
    		pushup(k);
    	}
    	void clear(int k,int l,int r,int pos)
    	{
    		if(l==r)
    		{
    			tr[k]=-inf;
    			return;
    		}
    		int mid=(l+r)>>1;
    		if(pos<=mid)clear(lson,l,mid,pos);
    		else clear(rson,mid+1,r,pos);
    		pushup(k);
    	}
    	int ask(int k,int l,int r,int x,int y)
    	{
    		if(x<=l&&r<=y)return tr[k];
    		int mid=(l+r)>>1,res=-inf;
    		if(x<=mid)res=max(res,ask(lson,l,mid,x,y));
    		if(mid+1<=y)res=max(res,ask(rson,mid+1,r,x,y));
    		return res;
    	}
    }pre,now;
    namespace solve2
    {
    	int root,num,ans=-inf;
    	int vis[N],siz[N],mx[N];
    	void Groot(int x,int fa)
    	{
    		siz[x]=1;mx[x]=0;
    		for(int i=0,Siz=v[x].size();i<Siz;++i)
    			if(!vis[v[x][i].to]&&v[x][i].to!=fa)
    			{
    				Groot(v[x][i].to,x);
    				siz[x]+=siz[v[x][i].to];mx[x]=max(mx[x],siz[v[x][i].to]);
    			}
    		mx[x]=max(mx[x],num-siz[x]);
    		if(mx[x]<mx[root])root=x;
    	}
    	void dfs1(int x,int fa,int dep,int sum,int last,int se)
    	{
    		if(r-dep<=0)return;
    		if(l<=dep&&dep<=r)ans=max(ans,sum);
    		ans=max(ans,sum+pre.ask(1,1,n,max(1,l-dep),r-dep));
    		ans=max(ans,sum+now.ask(1,1,n,max(1,l-dep),r-dep)-c[se]);
    		for(int i=0,Siz=v[x].size();i<Siz;++i)
    			if(!vis[v[x][i].to]&&v[x][i].to!=fa)dfs1(v[x][i].to,x,dep+1,sum+(v[x][i].c==last?0:c[v[x][i].c]),v[x][i].c,se);
    	}
    	void dfs2(int x,int fa,int dep,int sum,int last)
    	{
    		if(r-dep<=0)return;
    		now.change(1,1,n,dep,sum);
    		for(int i=0,Siz=v[x].size();i<Siz;++i)
    			if(!vis[v[x][i].to]&&v[x][i].to!=fa)dfs2(v[x][i].to,x,dep+1,sum+(v[x][i].c==last?0:c[v[x][i].c]),v[x][i].c);
    	}
    	void dfs3(int x,int fa,int dep,int sum,int last)
    	{
    		if(r-dep<=0)return;
    		now.clear(1,1,n,dep);pre.change(1,1,n,dep,sum);
    		for(int i=0,Siz=v[x].size();i<Siz;++i)
    			if(!vis[v[x][i].to]&&v[x][i].to!=fa)dfs3(v[x][i].to,x,dep+1,sum+(v[x][i].c==last?0:c[v[x][i].c]),v[x][i].c);
    	}
    	void dfs4(int x,int fa,int dep,int sum,int last)
    	{
    		if(r-dep<=0)return;
    		pre.clear(1,1,n,dep);
    		for(int i=0,Siz=v[x].size();i<Siz;++i)
    			if(!vis[v[x][i].to]&&v[x][i].to!=fa)dfs4(v[x][i].to,x,dep+1,sum+(v[x][i].c==last?0:c[v[x][i].c]),v[x][i].c);
    	}
    	void dfs5(int x,int fa,int dep,int sum,int last)
    	{
    		if(r-dep<=0)return;
    		now.clear(1,1,n,dep);
    		for(int i=0,Siz=v[x].size();i<Siz;++i)
    			if(!vis[v[x][i].to]&&v[x][i].to!=fa)dfs5(v[x][i].to,x,dep+1,sum+(v[x][i].c==last?0:c[v[x][i].c]),v[x][i].c);
    	}
    	void solve(int x)
    	{
    		vis[x]=1;
    		int Siz=v[x].size();
    		sort(v[x].begin(),v[x].end());
    		
    		for(int i=0;i<Siz;++i)
    			if(!vis[v[x][i].to])
    			{
    				if(i!=0&&v[x][i].c!=v[x][i-1].c)
    				{
    					for(int j=i-1;j>=0&&v[x][j].c==v[x][i-1].c;--j)
    						if(!vis[v[x][j].to])dfs3(v[x][j].to,x,1,c[v[x][j].c],v[x][j].c);
    				}
    				dfs1(v[x][i].to,x,1,c[v[x][i].c],v[x][i].c,v[x][i].c);
    				dfs2(v[x][i].to,x,1,c[v[x][i].c],v[x][i].c);
    			}
    		for(int i=0;i<Siz;++i)
    			if(!vis[v[x][i].to])dfs4(v[x][i].to,x,1,c[v[x][i].c],v[x][i].c);
    		for(int i=Siz-1;i>=0&&v[x][i].c==v[x][Siz-1].c;--i)
    			if(!vis[v[x][i].to])dfs5(v[x][i].to,x,1,c[v[x][i].c],v[x][i].c);
    		
    		for(int i=0;i<Siz;++i)
    			if(!vis[v[x][i].to])root=0,num=siz[v[x][i].to],Groot(v[x][i].to,0),solve(root);
    	}
    	void work()
    	{
    		pre.build(1,1,n);now.build(1,1,n);
    		mx[0]=1<<30;root=0;num=n;Groot(1,0);solve(root);
    		cout<<ans;
    	}
    }
    int main()
    {
    	cin>>n>>m>>l>>r;
    	for(int i=1;i<=m;++i)c[i]=read();
    	for(int i=1,x,y,z;i<n;++i)
    	{
    		x=read(),y=read(),z=read();
    		v[x].push_back((bian){y,z});
    		v[y].push_back((bian){x,z});
    	}
    	if(n<=1000)solve1::work();
    	else solve2::work();
    	return 0;
    }
    
  • 相关阅读:
    MySQL主从复制
    Mysql解压版安装配置
    MySQL 多行数据合并 GROUP_CONCAT
    Java集合框架
    Redis 入门知识点
    事务
    Spring AOP 知识点入门
    Tomcat热部署和热加载
    Java的Socket通信简单实例
    nginx和tomcat配置负载均衡和session同步
  • 原文地址:https://www.cnblogs.com/wljss/p/13370827.html
Copyright © 2020-2023  润新知