1. 程式人生 > >[2016北京集訓試題14]股神小D-[LCT]

[2016北京集訓試題14]股神小D-[LCT]

col 分享 font scrip pla get 一個數 試題 北京

Description

技術分享圖片

Solution

將(u,v,l,r)換為(1,u,v,l)和(2,u,v,r)。進行排序(第4個數為第一關鍵字,第1個數為第二關鍵字)。用LCT維護聯通塊的合並和斷開。(維護聯通塊的大小,要維護虛邊)

答案統計:每當四元組的第一個數為1(這時候合並點u,v所在連通塊,反之拆開),在合並前ans+=size[u]*size[v]即可。

Code

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cmath>
using
namespace std; const int N=2e5+10; long long ans; struct LCT { int val[N],sz[N],v[N],fa[N],ch[N][2],rev[N]; bool isroot(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;} bool get(int x){return ch[fa[x]][1]==x;} void updata(int x){sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+v[x]+1;} void
rotate(int x) { int k=get(x),y=fa[x]; ch[y][k]=ch[x][k^1];fa[ch[y][k]]=y; if (!isroot(y)) ch[fa[y]][ch[fa[y]][1]==y]=x;fa[x]=fa[y]; fa[y]=x;ch[x][k^1]=y; updata(y); updata(x); } void pushdown(int x) { if (rev[x]) { swap(ch[x][
0],ch[x][1]); rev[ch[x][0]]^=1;rev[ch[x][1]]^=1; rev[x]=0; } } int q[N],cnt; void splay(int x) { int y; q[cnt=1]=x; for (int i=x;!isroot(i);i=fa[i]) q[++cnt]=fa[i]; for (int i=cnt;i>=1;i--) pushdown(q[i]),fa[q[i]]=fa[q[i]]; while (!isroot(x)) { y=fa[x]; if (!isroot(y)) rotate(get(x)==get(y)?y:x); rotate(x); } } void access(int x) { int y=0; while (x) { splay(x); v[x]+=sz[ch[x][1]]-sz[y]; ch[x][1]=y; updata(x); y=x;x=fa[x]; } } void mroot(int x) { access(x);splay(x);rev[x]^=1; } void link(int x,int y) { mroot(x);access(y);splay(y); ans+=1ll*sz[x]*sz[y]; fa[x]=y;v[y]+=sz[x];updata(y); } void cut(int x,int y) { mroot(x);access(y);splay(y); fa[x]=ch[y][0]=0; updata(y); } }lct; int n,u,v,l,r; struct Q{int t,u,v,w; friend bool operator <(Q a,Q b){return a.w==b.w?a.t<b.t:a.w<b.w;} }q[N<<1]; int main() { scanf("%d",&n); for (int i=1;i<n;i++) { scanf("%d%d%d%d",&u,&v,&l,&r); q[i*2-1]=Q{1,u,v,l};q[i*2]=Q{2,u,v,r}; } sort(q+1,q+2*n-1); for (int i=1;i<=2*n-2;i++) { if (q[i].t==1) lct.link(q[i].u,q[i].v); else lct.cut(q[i].u,q[i].v); } cout<<ans; }

[2016北京集訓試題14]股神小D-[LCT]