[边分治+线段树合并]「CTSC2018」暴力写挂
生活随笔
收集整理的這篇文章主要介紹了
[边分治+线段树合并]「CTSC2018」暴力写挂
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目梗概
給出兩棵1為根的樹,求\(d[x]+d[y]-d[lca(x,y)]-d'[lca(x,y)]\)的最大值
解題思路
套路化簡之后\((d[x]+d[y]+dis(x,y)-2*d'[lca(x,y)])/2\)
第二棵樹上的lca化不掉,所以考慮在第二棵上枚舉lca
先說說這題的解法,邊分樹的合并.
邊分和點分有什么區別,邊分在合并類似\(d[x]+d[y]+dis(x,y)\)這種貢獻是很方便,只要記錄一條邊兩端的點集中\(d[x]+dis(x,u)\)最大值即可,而點分合并這種貢獻時復雜度與度數有關.
所以我們邊分治第一棵樹,建出邊分樹之后,遍歷第二棵樹,每次加入一個點,在邊分樹上維護答案
考慮左右兒子的答案如何合并,因為邊分樹是二叉樹,像線段樹一樣合并即可,復雜度\(O(n\) \(log n)\).
邊分治:將原圖轉成二叉樹(保證復雜度),每次找左右兩端節點數最大值最小的邊分開即可.
#include<cstdio> #include<vector> #include<cstring> #include<algorithm> #define LL long long using namespace std; const int maxn=370005; const LL INF=(LL)1e18; inline int _read(){int num=0,f=1;char ch=getchar();while(ch<'0'||ch>'9'){if (ch=='-') f=-1;ch=getchar();}while(ch>='0'&&ch<='9') num=num*10+ch-48,ch=getchar();return f*num; } struct jz{int x,y,w;jz(int x=0,int y=0,int w=0):x(x),y(y),w(w){} }; int lnk[maxn<<2],son[maxn<<3],nxt[maxn<<3],w[maxn<<3],tot=1; int n,cnt,zo,rx,ry,mi,rh,s[maxn<<2],rs[maxn<<3],ls[maxn<<3],d[maxn<<2],val[maxn<<3],fa[maxn<<3]; int rt[maxn],id,lc[maxn*46],rc[maxn*46],h[maxn*46]; LL rw[maxn*46],lw[maxn*46],dis[23][maxn<<2],ans=-INF; vector<jz> Q; bool vis[maxn<<3]; void add(int x,int y,int z){nxt[++tot]=lnk[x];lnk[x]=tot;son[tot]=y;w[tot]=z;} void DFS(int x,int fa){int pre=x;for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa){Q.push_back(jz(pre,son[j],w[j]));Q.push_back(jz(pre,++cnt,0));pre=cnt;DFS(son[j],x);} } void get_ro(int x,int fa,int dep,int lst){s[x]=1;for (int j=lnk[x];j;j=nxt[j]) if (!vis[j]&&son[j]!=fa){dis[dep][son[j]]=dis[dep][x]+w[j];get_ro(son[j],x,dep,j),s[x]+=s[son[j]];}int w=max(zo-s[x],s[x]);if (w<=mi) mi=w,rx=x,ry=fa,rh=lst; } int work(int x,int dep,int sz){if (sz<=1) return d[x]=dep,x;mi=zo=sz;int now=++cnt;get_ro(x,0,dep,0);vis[rh]=vis[rh^1]=1;val[now]=w[rh];int X=rx,Y=ry;rs[now]=work(Y,dep+1,sz-s[X]);ls[now]=work(X,dep+1,s[X]);fa[ls[now]]=fa[rs[now]]=now;return now; } int add(int x){int lst=0,now=x;for (int i=d[x];i;i--){h[++id]=fa[now];lw[id]=rw[id]=-INF; if (now==ls[fa[now]]) lw[id]=dis[i][x]+dis[0][x],lc[id]=lst;if (now==rs[fa[now]]) rw[id]=dis[i][x]+dis[0][x],rc[id]=lst;lst=id;now=fa[now];}return id; } void merge(int &x,int y,LL dep){if (!x||!y){x=x+y;return;}ans=max(ans,lw[x]+rw[y]+val[h[x]]-dep);ans=max(ans,lw[y]+rw[x]+val[h[x]]-dep);lw[x]=max(lw[x],lw[y]);rw[x]=max(rw[x],rw[y]);merge(lc[x],lc[y],dep);merge(rc[x],rc[y],dep); } void solve(int x,int fa,LL dep){rt[x]=add(x);ans=max(ans,dis[0][x]*2-dep*2);for (int j=lnk[x];j;j=nxt[j]) if (son[j]!=fa){solve(son[j],x,dep+w[j]);merge(rt[x],rt[son[j]],dep*2);}} int main(){freopen("exam.in","r",stdin);freopen("exam.out","w",stdout);n=_read();cnt=n;for (int i=1;i<n;i++){int x=_read(),y=_read(),z=_read();add(x,y,z);add(y,x,z);}DFS(1,0);memset(lnk,0,sizeof(lnk));tot=1;for (int i=0;i<Q.size();i++) add(Q[i].x,Q[i].y,Q[i].w),add(Q[i].y,Q[i].x,Q[i].w);work(1,0,cnt);memset(lnk,0,sizeof(lnk));tot=1;for (int i=1;i<n;i++){int x=_read(),y=_read(),z=_read();add(x,y,z);add(y,x,z);}solve(1,0,0);printf("%lld\n",ans/2);return 0; }轉載于:https://www.cnblogs.com/CHNJZ/p/10554011.html
總結
以上是生活随笔為你收集整理的[边分治+线段树合并]「CTSC2018」暴力写挂的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: CSS3 Media Queries在i
- 下一篇: 502 Bad Gateway ngin