zoukankan      html  css  js  c++  java
  • 【BZOJ2870】—最长道路Tree(边分治)

    传送门


    边分治比点分治好的一点就是每次分出来都只有2个集合
    如果遇到难以合并的信息的时候边分治就很有用了

    手动转二叉树

    每次可以按照权值大小排序后对两个集合双指针扫两遍
    具体实现可以看代码

    复杂度O(nlog2n)O(nlog^2n)

    #include<bits/stdc++.h>
    using namespace std;
    const int RLEN=1<<20|1;
    #define ll long long
    #define pb push_back
    #define pii pair<int,int>
    #define gc getchar
    inline int read(){
    	char ch=gc();
    	int res=0,f=1;
    	while(!isdigit(ch))f^=ch=='-',ch=gc();
    	while(isdigit(ch))res=(res+(res<<2)<<1)+(ch^48),ch=gc();
    	return f?res:-res;
    }
    const int N=200005;
    const int inf=1e9;
    int n,pn,mx,mxsiz,tot,rt;
    ll ans;
    int adj[N],nxt[N<<1],to[N<<1],siz[N],val[N<<1],vis[N<<1],cnt=1,pt[2],a[N];
    pii tmp[2][N];
    #define fi first
    #define se second
    inline bool comp(const pii &a,const pii &b){
    	return a.fi>b.fi;
    }
    vector<int> son[N];
    inline void addedge(int u,int v,int w){
    	nxt[++cnt]=adj[u],adj[u]=cnt,to[cnt]=v,val[cnt]=w;
    }
    void dfs(int u,int f){
    	for(int e=adj[u];e;e=nxt[e]){
    		int v=to[e];
    		if(v==f)continue;
    		son[u].pb(v),dfs(v,u);
    	}
    }
    inline void rebuild(){
    	cnt=1;memset(adj,0,sizeof(adj));
    	for(int u=1;u<=n;u++){
    		if(son[u].size()<=2){
    			for(int i=0,len=son[u].size();i<len;i++){
    				int v=son[u][i];
    				addedge(u,v,v<=pn),addedge(v,u,v<=pn);
    			}
    		}
    		else{
    			int f1=++n,f2=++n;a[f1]=a[f2]=a[u];
    			addedge(u,f1,0),addedge(f1,u,0),addedge(f2,u,0),addedge(u,f2,0);
    			for(int i=0,len=son[u].size();i<len;i++){
    				if(i&1)son[f2].pb(son[u][i]);
    				else son[f1].pb(son[u][i]);
    			}
    		}
    	}
    }
    inline void getrt(int u,int f){
    	siz[u]=1;
    	for(int e=adj[u];e;e=nxt[e]){
    		int v=to[e];
    		if(vis[e>>1]||v==f)continue;
    		getrt(v,u),siz[u]+=siz[v];
    		int k=max(siz[v],mxsiz-siz[v]);
    		if(k<mx)mx=k,rt=e;
    	}
    }
    void getdis(int kd,int u,int f,int dep,int va){
    	va=min(va,a[u]),tmp[kd][++pt[kd]]=pii(va,dep);
    	for(int e=adj[u];e;e=nxt[e]){
    		int v=to[e];
    		if(vis[e>>1]||v==f)continue;
    		getdis(kd,v,u,dep+val[e],va);
    	}
    }
    void solve(int u,int sz){
    	mxsiz=sz,mx=inf;
    	getrt(u,0);
    	if(mx==inf)return;
    	int now=rt;vis[now>>1]=1;
    	pt[0]=pt[1]=0,getdis(0,to[now],0,0,inf),getdis(1,to[now^1],0,0,inf);
    	sort(tmp[0]+1,tmp[0]+pt[0]+1,comp),sort(tmp[1]+1,tmp[1]+pt[1]+1,comp);
    	for(int i=1,j=1,mxl=0;i<=pt[0];i++){
    		while(j<=pt[1]&&tmp[1][j].fi>=tmp[0][i].fi)mxl=max(mxl,tmp[1][j].se),j++;
    		if(j!=1)ans=max(ans,1ll*tmp[0][i].fi*(mxl+tmp[0][i].se+val[now]+1));
    	}
    	for(int i=1,j=1,mxl=0;i<=pt[1];i++){
    		while(j<=pt[0]&&tmp[0][j].fi>=tmp[1][i].fi)mxl=max(mxl,tmp[0][j].se),j++;
    		if(j!=1)ans=max(ans,1ll*tmp[1][i].fi*(mxl+tmp[1][i].se+val[now]+1));
    	}
    	int ksz=siz[to[now]];solve(to[now],ksz),solve(to[now^1],sz-ksz);
    }
    int main(){
    	n=pn=read();
    	for(int i=1;i<=n;i++)a[i]=read();
    	for(int i=1;i<n;i++){
    		int u=read(),v=read();
    		addedge(u,v,1),addedge(v,u,1);
    	}
    	dfs(1,0),rebuild(),solve(1,n);
    	cout<<ans;
    }
    
  • 相关阅读:
    第1条:考虑用静态工厂方法代替构造器
    代理模式(Proxy Pattern)
    out 和 ref 参数修饰符
    SQL Server 性能调优(一)——从等待状态判断系统资源瓶颈【转】
    Windows下获取Dump文件以及进程下各线程调用栈的方法总结(转)
    sql server内置函数
    ORA-16019 和 ORA-16018 错误的处理方法(转)
    marge into操作
    LogMiner配置使用手册
    课后作业
  • 原文地址:https://www.cnblogs.com/stargazer-cyk/p/11145551.html
Copyright © 2011-2022 走看看