zoukankan      html  css  js  c++  java
  • 边分治学习笔记

    对于某些点分治不太好合并两条链的信息的题,可以考虑使用边分治;
    边分治时的主要思想跟点分治一样,一直去找某个重心,把一棵树不断化成更小的部分,边分治需要找的这个重心在边上,使得去掉这条边过后两边剩的点的差最小,写法跟点分治都差不多,但是边分治会被菊花图这样的树给卡成(n^2),所以在边分治之前要重构原树,把原树变成一棵二叉树,具体做法就是新建虚节点然后把真实儿子放在虚二叉树的叶子节点上,这样做就没有数据能把边分治卡下来,空间参考堆式线段树的算法,变成了(4n)的样子;
    边分治每次把当前联通快分成了两坨,计算贡献也比点分治方便多了;
    以下边分治部分的代码自己yy的,可能写丑了或者傻逼自带大常数了;

    例题 BZOJ#2870

    /*
    	Name: BZOJ#2870
    	Author: CIao
    	Date: 09/03/19 17:08
    	Description: 边分治 
    */
    #include<bits/stdc++.h>
    #define Fst first
    #define Snd second
    #define RG register
    #define mp make_pair
    #define mem(a,b) memset(a,b,sizeof(a))
    using namespace std;
    typedef long long LL;
    typedef long double LD;
    typedef unsigned int UI;
    typedef unsigned long long ULL;
    template<typename T> inline void read(T& x) {
    	char c = getchar();
    	bool f = false;
    	for (x = 0; !isdigit(c); c = getchar()) {
    		if (c == '-') {
    			f = true;
    		}
    	}
    	for (; isdigit(c); c = getchar()) {
    		x = x * 10 + c - '0';
    	}
    	if (f) {
    		x = -x;
    	}
    }
    template<typename T, typename... U> inline void read(T& x, U& ... y) {
    	read(x), read(y...);
    }
    const int INF=65536+1,N=2e5+10;
    int n,p=1,O,Ed,TOT,size,root,MAXV,TMP;
    int head[N],A[N],V[N],num[N];
    LL ANS;
    bool G[N],No[N<<1];
    vector<int> E[N];
    struct Edge {
    	int to,last,w;
    	Edge () {}
    	Edge (int a,int b,int c) :to(a),last(b),w(c) {}
    }edge[N<<1];
    void ADD(int a,int b,int c) {
    	edge[++p]=Edge(b,head[a],c); head[a]=p;
    	edge[++p]=Edge(a,head[b],c); head[b]=p;
    }
    void Build(int l,int r,int f) {
    	if(l>r) return;
    	if(l==r) {
    		ADD(f,V[l],1);
    		return;
    	}
    	int mid=l+r>>1,rt=++n; A[rt]=A[f];
    	ADD(f,rt,0);
    	Build(l,mid,rt); Build(mid+1,r,rt);
    }
    void DFS(int u,int f) {
    	int cnt=0;
    	for(int i=0;i<(int)E[u].size();++i) if(E[u][i]!=f) V[++cnt]=E[u][i];
    	int mid=1+cnt>>1;
    	Build(1,mid,u); Build(mid+1,cnt,u);
    	for(int i=0;i<(int)E[u].size();++i) if(E[u][i]!=f) DFS(E[u][i],u);
    }
    void GetEdge(int u,int f) {
    	num[u]=1;
    	for(int i=head[u];i;i=edge[i].last) {
    		int v=edge[i].to;
    		if(!No[i]&&v!=f) {
    			GetEdge(v,u);
    			num[u]+=num[v];
    		}
    	}
    	for(int i=head[u];i;i=edge[i].last) {
    		int v=edge[i].to;
    		if(!No[i]&&v!=f) {
    			if(MAXV>abs(TOT-num[v]*2)) {
    				root=u; Ed=i;
    				MAXV=abs(TOT-num[v]*2);
    			}
    		}
    	}
    }
    int cnt,tot;
    struct Data {
    	int val,dis;
    }F[N],P[N];
    void Getdis(int u,int f,int val,int dis) {
    	val=min(val,A[u]);
    	if(G[u]) {
    		F[++cnt]=(Data){val,dis+1};
    		ANS=max(ANS,1ll*(dis+1)*val);
    	}
    	for(int i=head[u];i;i=edge[i].last) {
    		int v=edge[i].to;
    		if(!No[i]&&v!=f) Getdis(v,u,val,dis+edge[i].w);
    	}
    }
    void Calc(int u,int f,int val,int dis) {
    	val=min(val,A[u]);
    	if(G[u]) P[++tot]=(Data){val,dis+TMP};
    	for(int i=head[u];i;i=edge[i].last) {
    		int v=edge[i].to;
    		if(!No[i]&&v!=f) Calc(v,u,val,dis+edge[i].w);
    	}
    }
    bool cmp(Data A,Data B) {
    	return A.val==B.val?A.dis<B.dis:A.val<B.val;
    }
    void Solve() {
    	if(!cnt||!tot) return;
    	sort(F+1,F+cnt+1,cmp); sort(P+1,P+tot+1,cmp);
    	for(int i=cnt-1;i;--i) F[i].dis=max(F[i].dis,F[i+1].dis);
    	int now=1;
    	for(int i=1;i<=tot;++i) {
    		while(now!=cnt&&F[now].val<P[i].val) ++now;
    		if(F[now].val>=P[i].val) ANS=max(ANS,1ll*P[i].val*(P[i].dis+F[now].dis));
    	}
    }
    void DAC(int u1,int e) {
    	if(e==-1) return;
    	int u2=edge[e].to; No[e]=No[e^1]=true; TMP=edge[e].w;
    	cnt=tot=0; Getdis(u1,0,INF,0); Calc(u2,0,INF,0); Solve();
    	cnt=tot=0; Getdis(u2,0,INF,0); Calc(u1,0,INF,0); Solve();
    	int S1=TOT-num[u2],S2=num[u2];
    	root=u1; Ed=-1; MAXV=S1+1; TOT=S1; GetEdge(u1,0); DAC(root,Ed);
    	root=u2; Ed=-1; MAXV=S2+1; TOT=S2; GetEdge(u2,0); DAC(root,Ed);
    }
    //#define rua
    int main() {
    //	ios::sync_with_stdio(false);
    #ifdef rua
    #endif
    	read(n);
    	for(int i=1;i<=n;++i) read(A[i]),G[i]=true;
    	for(int i=1;i<n;++i) {
    		int u,v; read(u,v);
    		E[u].push_back(v); E[v].push_back(u);
    	}
    	DFS(1,0);
    	root=1; Ed=-1; MAXV=n+1; TOT=n; GetEdge(1,0);
    	DAC(root,Ed);
    	printf("%lld
    ",ANS);
    	return 0;
    }
    
    
  • 相关阅读:
    JavaScript设计模式与开发实践 适配器模式
    JavaScript设计模式与开发实践 状态模式
    JavaScript设计模式与开发实践 装饰者模式
    JavaScript设计模式与开发实践 中介者模式
    JavaScript设计模式与开发实践 职责链模式
    meta标签属性
    在制作网站之前,前端程序员应该考虑哪些技术细节?
    JavaScript设计模式与开发实践 享元模式
    JavaScript设计模式与开发实践 模板方法模式
    梯度下降法
  • 原文地址:https://www.cnblogs.com/ak12/p/10502106.html
Copyright © 2011-2022 走看看