zoukankan      html  css  js  c++  java
  • uoj#400. 【CTSC2018】暴力写挂(边分治)

    传送门

    做一道题学一堆东西.jpg

    猫老师的题……暴力拿的分好像比打挂的正解多很多啊……我纯暴力+部分分已经能有80了……正解没调对之前一直只有10分→_→

    先说一下什么是边分治。这个其实类似于点分治,不过分治对象从点换成边了,就是每次找到一条边,使其断开之后的两个连通块中最大的最小

    于是我们就可以……等会儿如果在菊花图上怎么办?不是得卡到(O(n^2))了?

    不难发现这个东西的复杂度和节点的度数有关,于是为了假装这个东西能用避免这些情况,我们要把图给重构喽

    简单来说就是通过加入虚点,把图给搞成一棵二叉树,这样的话节点度数就小了,复杂度也没问题了

    原理大概就这样,具体实现还是看代码比较好

    然后回到本题

    首先在第二棵树上的(LCA)的深度它就不是个东西,我们只能去枚举它,那么能选的点就是它的不同子树中的点了

    然后考虑转化一下,$$dep(x) + dep(y) - dep(LCA(x,y))=frac{1}{2}(dep(x) + dep(y) + dis(x,y))$$
    然后我们就可以把它给转化成一棵无根树了

    在分治过程中,对于每条边((i,j)),要维护两边子树中中最大的(dep_u+dis_{i,u})(dep_v+dis_{j,v}),然后用自己这条边更新答案

    然后因为边分树是一棵二叉树,我们可以用线段树来维护上面的信息

    然后就没有然后了(就算有然后我也布吉岛是怎么回事)

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define ll long long
    #define inf 1e18
    #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
    #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
    #define go(T,u) for(int i=T.head[u],v=T.e[i].v;i;i=T.e[i].nx,v=T.e[i].v)
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
        R int res,f=1;R char ch;
        while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
        for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
        return res*f;
    }
    const int N=7.5e5+5;
    struct eg{int v,nx,w;}st[N];
    struct Gr{
    	eg e[N<<1];int head[N],tot;
    	inline void add(R int u,R int v,R int w){e[++tot]={v,head[u],w},head[u]=tot;}
    }T,G,H;
    ll toroot[N];
    int n,cnt;
    void rebuild(int u,int fa){
    	int h=1,t=0;
    	go(T,u)if(v!=fa)toroot[v]=toroot[u]+T.e[i].w,rebuild(v,u);
    	go(T,u)if(v!=fa)st[++t]=T.e[i];
    	while(t-h>=2){
    		eg s1=st[h++],s2=st[h++];
    		int w=++cnt;st[++t]={w,0,0};
    		H.add(w,s1.v,s1.w),H.add(s1.v,w,s1.w);
    		H.add(w,s2.v,s2.w),H.add(s2.v,w,s2.w);
    	}
    	while(h<=t)H.add(u,st[h].v,st[h].w),H.add(st[h].v,u,st[h].w),++h;
    }
    int ls[N<<1],rs[N<<1],fa[N<<1],dif[N],sz[N],dep[N],val[N<<1];ll dis[25][N];
    int size;
    void getdis(int u,int fat,int dep){
    	go(H,u)if(v!=fat&&v!=-1){
    		dis[dep][v]=dis[dep][u]+H.e[i].w;
    		getdis(v,u,dep);
    	}
    }
    void getgr(int u,int fat,int &g1,int &g2){
    	sz[u]=1;
    	go(H,u)if(v!=fat&&v!=-1){
    		getgr(v,u,g1,g2),sz[u]+=sz[v];
    		if(dif[g2]>dif[v])g1=u,g2=v;
    	}dif[u]=abs(size-(sz[u]<<1));
    }
    int gettr(int u,int dep,int s){
    	if(s==1)return ::dep[u]=dep,u;
    	getdis(u,0,dep);
    	int now=++cnt,g1=0,g2=0;
    	size=s,getgr(u,0,g1,g2);
    	go(H,g1)if(v==g2){val[now]=H.e[i].w,H.e[i].v=-1;break;}
    	go(H,g2)if(v==g1){H.e[i].v=-1;break;}
    	rs[now]=gettr(g1,dep+1,size-sz[g2]);
    	ls[now]=gettr(g2,dep+1,sz[g2]);
    	fa[ls[now]]=fa[rs[now]]=now;
    	return now;
    }
    void init(){
    	cnt=n,rebuild(1,0);
    	dif[0]=0x3f3f3f3f,gettr(1,0,cnt);
    }
    ll lv[N<<4],rv[N<<4],res;
    int id,mp[N<<4],rt[N],lp[N<<4],rp[N<<4];
    int merge(int x,int y,ll d){
    	if(!x||!y)return x|y;
    	cmax(res,((lv[x]+rv[y]+val[mp[x]])>>1)-d);
    	cmax(res,((rv[x]+lv[y]+val[mp[x]])>>1)-d);
    	cmax(lv[x],lv[y]),lp[x]=merge(lp[x],lp[y],d);
    	cmax(rv[x],rv[y]),rp[x]=merge(rp[x],rp[y],d);
    	return x;
    }
    int ins(int u){
    	for(int i=dep[u],x=u,las=0;i;--i,las=cnt,u=fa[u]){
    		mp[++cnt]=fa[u];
    		lv[cnt]=rv[cnt]=-inf;
    		if(u==ls[fa[u]])cmax(lv[cnt],dis[i][x]+toroot[x]),lp[cnt]=las;
    		else cmax(rv[cnt],dis[i][x]+toroot[x]),rp[cnt]=las;
    	}return cnt;
    }
    void solve(int u,int fat,ll d){
    	rt[u]=ins(u),cmax(res,toroot[u]-d);
    	go(G,u)if(v!=fat){
    		solve(v,u,d+G.e[i].w);
    		rt[u]=merge(rt[u],rt[v],d);
    	}
    }
    int u,v,w;
    int main(){
    //	freopen("testdata.in","r",stdin);
    	n=read();
    	fp(i,1,n-1)u=read(),v=read(),w=read(),T.add(u,v,w),T.add(v,u,w);
    	fp(i,1,n-1)u=read(),v=read(),w=read(),G.add(u,v,w),G.add(v,u,w);
    	init(),solve(1,0,0);
    	printf("%lld
    ",res);
    	return 0;
    }
    
  • 相关阅读:
    C#(二)变量
    WinForm(一)基础
    面向对象(二) 继承和多态
    面向对象 (三)抽象类和接口
    面向对象 基础
    面向对象(一)封装 命名空间 访问修饰符等
    C#跳转语句 迭代法 穷举法
    C# 异常处理语句
    C# while循环
    Request和Response
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10269178.html
Copyright © 2011-2022 走看看