• 边分治学习笔记


    对于某些点分治不太好合并两条链的信息的题,可以考虑使用边分治;
    边分治时的主要思想跟点分治一样,一直去找某个重心,把一棵树不断化成更小的部分,边分治需要找的这个重心在边上,使得去掉这条边过后两边剩的点的差最小,写法跟点分治都差不多,但是边分治会被菊花图这样的树给卡成(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;
    }
    
    
  • 相关阅读:
    用FOR XML PATH('') 实现一列多行拼接为一行
    RTC相关文章收集
    XML-RPC vs. RTC Format
    获取当前月份的第一天
    image读取流
    WAMP解决访问后显示"You don't have permission to access / on this server."
    cxGrid之checkbox小结
    CXGRID用法(取行、列值;定位选中某行等等)
    delphi显示Sqlite的Text字段
    使用TRoleAuth类对DataSnap服务端的接口授权
  • 原文地址:https://www.cnblogs.com/ak12/p/10502106.html
Copyright © 2020-2023  润新知