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\n",res);
    return 0;
}

原文地址:https://www.cnblogs.com/bztMinamoto/p/10269178.html

时间: 2024-10-08 23:44:01

uoj#400. 【CTSC2018】暴力写挂(边分治)的相关文章

CTSC2018 暴力写挂

CTSC2018 暴力写挂 题意: 题目传送门 题解: emm--第一次写边分治-- 考虑到第二棵树上的\(Lca\)我们难以处理,于是我们可以考虑枚举第二棵树上的\(Lca\),然后在第一棵树上最大化\(dep_u + dep_v - dep_{lca}\).但是在这个式子中,又受到了第一棵树上\(Lca\)的限制,于是我们考虑化简式子.稍微化简一下会发现式子变成了\(\frac{1}{2} * (dep_u + dep_v + dis_{u, v})\),然后我们就可以将其转化成无根树来做了

[CTSC2018]暴力写挂——边分树合并

[CTSC2018]暴力写挂 题面不错 给定两棵树,两点“距离”定义为:二者深度相加,减去两棵树上的LCA的深度(深度指到根节点的距离) 求最大的距离. 解决多棵树的问题就是降维了. 经典的做法是边分树合并. 边分树结构类似0/1 trie 就是把边分树对于每个点拆开路径 合并两棵边分树同时可以得到两个边分树之间点对的路径的信息 感觉有点类似线段树合并. 根据“猫树”思想,两点间的路径一定经过边分树上LCA的那条边.(u,v不相等) 我们考虑在这个LCA处统计贡献 具体地,先对1树进行边分治 每

UOJ#400. 【CTSC2018】暴力写挂 边分治 线段树合并

原文链接 www.cnblogs.com/zhouzhendong/p/UOJ400.html 前言 老年选手没有码力. 题解 先对第一棵树进行边分治,然后,设点 x 到分治中心的距离为 $D[x]$,点 x 在原树上的深度为 $d[x]$,那么 $$d[x]+d[y] - d[LCA(x,y)] - d'[LCA(x,y)] = \frac 12(D[x] + d[x]) + \frac 12 (D[y] + d[y]) - d'[LCA(x,y)]$$ 于是我们考虑将分治区域内的节点在第二棵

Loj #2553. 「CTSC2018」暴力写挂

Loj #2553. 「CTSC2018」暴力写挂 题目描述 temporaryDO 是一个很菜的 OIer .在 4 月,他在省队选拔赛的考场上见到了<林克卡特树>一题,其中 \(k = 0\) 的部分分是求树 \(T\) 上的最长链.可怜的 temporaryDO 并不会做这道题,他在考场上抓猫耳挠猫腮都想不出一点思路. 这时,善良的板板出现在了空中,他的身上发出璀璨却柔和的光芒,荡漾在考场上.''题目并不难.'' 板板说.那充满磁性的声音,让 temporaryDO 全身充满了力量. 他

暴力写挂

题目描述 题解 考虑把式子化一下,因为只有一个式子跟第二棵树有关,所以我们可以考虑把前面的式子化成跟 $\text{lca}$ 没有关系,即 $\frac{1}{2}(dp_u+dp_v+dis(u,v))$ .因此我们可以利用边分治,每次把两边的点黑白染色,构成虚树,然后做 $\text{dp}$ 即可.这里要注意 $\text{lca}$ 要 $O(1)$ 求,虚树构成过程中不能排序,故我们可以一开始就按照第二棵树的dfs排序好,之后分治下去即可.效率: $O(nlogn)$ . 代码 #i

如何快速正确的写出各种分治算法的实现代码

分治算法大家都很熟悉,很多时候(比如ACM竞赛)当我们判断出一个问题可以用分治算法来解决的时候,却往往因为具体的问题的复杂性,难以很快理清思路,迅速正确地写出问题的分治算法. 因此,要想快速正确的写出分治算法的实现代码,就必须足够的认识分治算法.直接看结论 一.认识分治 在分治策略中,我们递归地解决一个问题,在每层递归中应用如下三个步骤: 1.分解(Divide):将问题划分为一些子问题,子问题的形式与原问题一样,只是规模更小. 2.解决(Conquer):递归地求解出子问题.如果子问题规模足够

【uoj#244】[UER #7]短路 CDQ分治+斜率优化dp

题目描述 给出 $(2n+1)\times (2n+1)$ 个点,点 $(i,j)$ 的权值为 $a[max(|i-n-1|,|j-n-1|)]$ ,找一条从 $(1,1)$ 走到 $(2n+1,2n+1)$ 的路径,使得经过的点(包括起点和终点)权值和最小.求这个权值和. 输入 第一行一个正整数 $n$ . 第二行 $n+1$ 个正整数 $a[0],a[1],…,a[n]$ ,表示从内到外每层的中继器的延时值. 输出 输出一行一个数表示改造后的最短引爆时间. 样例输入 99 5 3 7 6 9

1134 最长递增子序列(暴力写的)

可以用二分写... 基准时间限制:1 秒 空间限制:131072 KB 分值: 0 难度:基础题  收藏  关注 给出长度为N的数组,找出这个数组的最长递增子序列.(递增子序列是指,子序列的元素是递增的) 例如:5 1 6 8 2 4 5 10,最长递增子序列是1 2 4 5 10. Input 第1行:1个数N,N为序列的长度(2 <= N <= 50000) 第2 - N + 1行:每行1个数,对应序列的元素(-10^9 <= S[i] <= 10^9) Output 输出最长

Luogu3793 由乃救爷爷 分块、ST表

传送门 因为昨天写暴力写挂在UOJ上用快排惨遭卡常,所以今天准备写一个卡常题消遣消遣,然后时间又垫底了QAQ 这道题显然需要支持一个\(O(N)\)预处理\(O(1)\)查询的ST表,显然普通的ST表是做不到的,因为预处理的时间太长了 于是分块优化掉ST表的预处理 约定\(L_i,R_i\)表示第\(i\)个块的左端点和右端点,\(be_i\)表示第\(i\)个数所在的块 对于每一个位置\(i\)预处理\(L_{be_i}\)到\(i\)的所有数的最大值\(lmax_i\)以及\(i\)到\(R