zoukankan      html  css  js  c++  java
  • P5306 [COCI2019] Transport

    题目

    P5306 [COCI2019] Transport

    分析

    点分治+平衡树。

    首先,我们很容易想到这里要使用点分治,然后我们可以考虑如何拼接路径。

    发现因为这道题这样的话是有方向的,于是可以考虑维护两个数据结构,一个是从这个点出发,一个是在这个点结束。

    那么具体怎么维护呢?我们发现对于一条路径是“在这里结束”类型的,它无论结果有多坏,只要记下它在路径上最坏的那一处,那么另外一条和它拼接的就只要能够使得最坏的那一处满足,那么剩下的肯定满足。

    而对于“从这里开始”类型的,它就必须是一直满足条件的状态,然后可以统计当前到根的剩下的多余的油,这个是拿去拼接的“资本”。

    由于这里的值域很大,我们不能直接树状数组了,于是可以考虑平衡树,这里使用了 (FHQ Treap)

    那么拼接就很好维护了,但是,我们发现这样的点对是有序的,所以我们在拼接的时候,只需要正着反着都做一遍,答案就统计完了。

    代码

    #include<bits/stdc++.h>
    using namespace std;
    template <typename T>
    inline void read(T &x){
        x=0;char ch=getchar();bool f=false;
        while(!isdigit(ch)) f|=ch=='-',ch=getchar();
        while(isdigit(ch)) x=(x<<1)+(x<<3)+(ch^48),ch=getchar();
        x=f?-x:x;return;
    }
    template <typename T>
    inline void write(T x){
        if(x<0) putchar('-'),x=-x;
        if(x>9) write(x/10);
        putchar(x%10^48);
    	return;
    }
    #define ll long long
    const int N=1e6+5;
    const ll INF=1e18+7;
    int n,a[N],idx,siz[N],vis[N],To[N],tmp,pool,root,w[N],Cnt,cnt;
    ll Ans,path[N],Now;
    struct FHQ_Treap{
    	int siz,key,rs,ls;
    	ll val;
    	#define ls(x) t[x].ls
    	#define rs(x) t[x].rs
    	#define key(x) t[x].key
    	#define val(x) t[x].val
    	#define siz(x) t[x].siz
    }t[N];
    inline void Update(int x){siz(x)=siz(ls(x))+siz(rs(x))+1;return ;}
    inline int NewNode(ll v){int x=++cnt;siz(x)=1,ls(x)=rs(x)=0,key(x)=rand(),val(x)=v;return x;}
    void Split(int now,ll k,int &x,int &y){
    	if(!now) return x=y=0,void();
    	if(val(now)<=k) x=now,Split(rs(x),k,rs(x),y);
    	else y=now,Split(ls(y),k,x,ls(y));
    	Update(now);
    	return ;
    }
    int Merge(int x,int y){
    	if(!x||!y) return x|y;
    	if(key(x)<=key(y)){rs(x)=Merge(rs(x),y);Update(x);return x;}
    	else{ls(y)=Merge(x,ls(y));Update(y);return y;}
    }
    void Insert(ll v){int x,y;Split(root,v,x,y);root=Merge(Merge(x,NewNode(v)),y);return ;}
    void Delete(ll v){int x,y,z;Split(root,v-1,x,y);Split(y,v,z,y);root=Merge(Merge(x,Merge(ls(z),rs(z))),y);return ;}
    int Query(ll v){
    	int x,y,z;
    	Split(root,v-1,x,y);
    	z=siz(y);
    	root=Merge(x,y);
    	return z;
    }
    bool Vis[N];
    int head[N],nex[N],to[N],val[N];
    void add(int u,int v,int w){
    	nex[++idx]=head[u];
    	to[idx]=v;
    	val[idx]=w;
    	head[u]=idx;
    	return ;
    }
    int Root,FMax,Size;
    void GetRoot(int x){
    	Vis[x]=true;siz[x]=1;int Max=0;
    	for(int i=head[x];i;i=nex[i]){
    		int y=to[i];
    		if(vis[y]||Vis[y]) continue;
    		GetRoot(y);siz[x]+=siz[y];
    		Max=max(Max,siz[y]);
    	}
    	Max=max(Max,Size-siz[x]);
    	if(Max<FMax) FMax=Max,Root=x;
    	Vis[x]=false;
    	return ;
    }
    void GetPath1(int x,int fa,ll Max,ll now){
    	Ans+=Query(Max);
    	for(int i=head[x];i;i=nex[i]){
    		int v=to[i];
    		if(v==fa||vis[v]) continue;
    		GetPath1(v,x,max(Max,now-a[x]+val[i]),now-a[x]+val[i]);
    	}
    }
    void GetPath2(int x,int fa,ll Max,ll now){
    	if(now>=Max) Insert(now),path[++Cnt]=now,Now++;
    	for(int i=head[x];i;i=nex[i]){
    		int v=to[i];
    		if(v==fa||vis[v]) continue;
    		GetPath2(v,x,max(now,Max),now+a[v]-val[i]);
    	}
    }
    void Calc(int x){
    	tmp=Cnt=Now=0;
    	for(int i=head[x];i;i=nex[i]){
    		int v=to[i];
    		if(vis[v]) continue;
    		To[++tmp]=v,w[tmp]=val[i];
    	}
    	for(int i=1;i<=tmp;i++){
    		GetPath1(To[i],x,w[i],w[i]);
    		GetPath2(To[i],x,a[x],a[x]+a[To[i]]-w[i]);
    	}
    	while(Cnt) Delete(path[Cnt--]);
    	Insert(a[x]);
    	for(int i=tmp;i>=1;i--){
    		GetPath1(To[i],x,w[i],w[i]);
    		GetPath2(To[i],x,a[x],a[x]+a[To[i]]-w[i]);
    	}
    	while(Cnt) Delete(path[Cnt--]);
    	Delete(a[x]);
    	Ans+=Now/2;
    	return ;
    }
    void DFS(int x){
    	Root=0,FMax=Size=siz[x];
    	GetRoot(x);
    	Calc(Root);
    	vis[Root]=true;
    	for(int i=head[Root];i;i=nex[i]){
    		int y=to[i];
    		if(vis[y]) continue;
    		DFS(y);
    	}
    }
    int main(){
    	read(n);
    	for(int i=1;i<=n;i++) read(a[i]);
    	int x,y,z;
    	for(int i=1;i<n;i++){
    		read(x),read(y),read(z);
    		add(x,y,z),add(y,x,z);
    	}
    	Root=0,siz[1]=n;
    	Insert(-(INF)),DFS(1);
    	write(Ans);
    	return 0;
    }
    
  • 相关阅读:
    .Net Core 为 x86 和 x64 程序集编写 AnyCPU 包装
    动态构造任意复杂的 Linq Where 表达式
    Windows GDI 窗口与 Direct3D 屏幕截图
    你一定看得懂的 DDD+CQRS+EDA+ES 核心思想与极简可运行代码示例
    浏览器中的 .Net Core —— Blazor WebAssembly 初体验
    Asp.Net Core IdentityServer4 管理面板集成
    Asp.Net Core Identity 骚断腿的究极魔改实体类
    lambda函数的作用
    风控模型师面试准备--业务+模型篇
    梯度下降算法原理讲解
  • 原文地址:https://www.cnblogs.com/Akmaey/p/14726858.html
Copyright © 2011-2022 走看看