• 【BZOJ5457】城市(线段树合并)


    点此看题面

    大致题意: 一棵树上每个点有颜色(a_i)和权值(b_i),求以每个点为根的子树内权值和最大的颜色及其权值和。

    线段树合并

    这是一道线段树合并板子题。

    (关于线段树合并,可参考我的这篇博客

    考虑一开始对于每个叶节点,在线段树第(a_i)位插入(b_i)

    然后,对于每个非叶节点,在其子节点求完答案后,依次合并其子节点的线段树,再在线段树第(a_i)位加上(b_i)

    重复此过程即可求出答案。

    注意当有多种颜色权值和相同时输出编号最小的颜色,一开始判错(WA)了好几发。

    代码

    #include<bits/stdc++.h>
    #define Tp template<typename Ty>
    #define Ts template<typename Ty,typename... Ar>
    #define Reg register
    #define RI Reg int
    #define Con const
    #define CI Con int&
    #define I inline
    #define W while
    #define N 400000
    #define LN 20
    #define add(x,y) (e[++ee].nxt=lnk[x],e[lnk[x]=ee].to=y)
    #define mp make_pair
    #define fir first
    #define sec second
    using namespace std;
    int n,m,ee,a[N+5],b[N+5],lnk[N+5],Rt[N+5],ans1[N+5],ans2[N+5];
    struct edge {int to,nxt;}e[N<<1];typedef pair<int,int> Pr;
    class FastIO
    {
    	private:
    		#define FS 100000
    		#define tc() (A==B&&(B=(A=FI)+fread(FI,1,FS,stdin),A==B)?EOF:*A++)
    		#define pc(c) (C==E&&(clear(),0),*C++=c)
    		#define tn (x<<3)+(x<<1)
    		#define D isdigit(c=tc())
    		int T;char c,*A,*B,*C,*E,FI[FS],FO[FS],S[FS];
    	public:
    		I FastIO() {A=B=FI,C=FO,E=FO+FS;}
    		Tp I void read(Ty& x) {x=0;W(!D);W(x=tn+(c&15),D);}
    		Ts I void read(Ty& x,Ar&... y) {read(x),read(y...);}
    		Tp I void write(Ty x) {W(S[++T]=x%10+48,x/=10);W(T) pc(S[T--]);}
    		Tp I void write(Con Ty& x,Con char& y) {write(x),pc(y);}
    		I void clear() {fwrite(FO,1,C-FO,stdout),C=FO;}
    }F;
    class SegmentTree//动态开点线段树
    {
    	private:
    		int tot,S[N*LN+5][2];Pr Mx[N*LN+5];
    		I void PU(CI x)//上传信息
    		{
    			if(Mx[S[x][0]].fir^Mx[S[x][1]].fir) Mx[x]=Mx[S[x][0]].fir>Mx[S[x][1]].fir?Mx[S[x][0]]:Mx[S[x][1]];//如果权值和不同,取权值和较大的
    			else Mx[x]=Mx[S[x][0]].sec<Mx[S[x][1]].sec?Mx[S[x][0]]:Mx[S[x][1]];//否则,取编号较小的
    		}
    	public:
    		I void Merge(CI l,CI r,int& x,CI y)//线段树合并
    		{
    			if(!x||!y) return (void)(x+=y);if(l==r) return (void)(Mx[x].fir+=Mx[y].fir);
    			RI mid=l+r>>1;Merge(l,mid,S[x][0],S[y][0]),Merge(mid+1,r,S[x][1],S[y][1]),PU(x);
    		}
    		I void Update(CI l,CI r,int& rt,CI x,CI v)//修改
    		{
    			if(!rt&&(rt=++tot),l==r) return (void)(Mx[rt]=mp(Mx[rt].fir+v,l));
    			RI mid=l+r>>1;x<=mid?Update(l,mid,S[rt][0],x,v):Update(mid+1,r,S[rt][1],x,v),PU(rt);
    		}
    		I Pr Query(CI rt) {return Mx[rt];}//询问
    }S;
    I void dfs(CI x,CI lst)//dfs遍历树
    {
    	RI i;for(i=lnk[x];i;i=e[i].nxt) e[i].to^lst&&(dfs(e[i].to,x),S.Merge(1,m,Rt[x],Rt[e[i].to]),0);//合并子节点的线段树
    	S.Update(1,m,Rt[x],a[x],b[x]);Pr t=S.Query(Rt[x]);ans1[x]=t.sec,ans2[x]=t.fir;//插入自身信息,并询问求出答案
    }
    int main()
    {
    	RI i,x,y;for(F.read(n,m),i=1;i^n;++i) F.read(x,y),add(x,y),add(y,x);//读入并建边
    	for(i=1;i<=n;++i) F.read(a[i],b[i]);//读入数据
    	for(dfs(1,0),i=1;i<=n;++i) F.write(ans1[i],' '),F.write(ans2[i],'
    ');//输出答案
    	return F.clear(),0;
    }
    
  • 相关阅读:
    software系列:Tableau10.5安装教程(破解版)
    技巧系列:Excel打印技巧
    Android 3.0 访问WebService 出现 android.os.NetworkOnMainThreadException异常
    Android各种布局
    服务器访问本地磁盘
    Android手机客户端访问.NET服务器端的方法(1)
    flex webservice
    android学习之 intent 实例
    Android手机客户端访问.NET服务器端的方法(2)
    一篇不错的讲解Java异常的文章(转载)感觉很不错,读了以后很有启发
  • 原文地址:https://www.cnblogs.com/chenxiaoran666/p/BZOJ5457.html
Copyright © 2020-2023  润新知