1. 程式人生 > >【分治】動態點分治 ([ZJOI2007]捉迷藏)

【分治】動態點分治 ([ZJOI2007]捉迷藏)

動態點分治

先看一道題目 [ZJOI2007]捉迷藏

顯然如果不帶修改O(N)的樹形動規和O(NlogN)的靜態點分治都可以切掉這道題

一、點分樹

考慮點分治,對於每一個分治區域樹的重心的答案只會與其所有子區域樹有關,所以我們可以再構建一顆點分樹:

在點分治的過程中,我們把每個區域樹的重心和其子區域樹的重心建立父子關係,形成了一顆新的樹,稱為點分樹。

點分樹的性質:1、一顆點分樹的深度為嚴格logN的

                         2、當修改一個結點事,只會對其父親結點造成影響z

二、維護結點資訊

對於這道題,我們只需維護每個結點上的最大鏈和次大鏈,我們可以對於每個結點建兩個大根堆:

A:關鍵字:原分治區域樹中以該結點為鏈的一段的所有鏈的長度

B:關鍵字:原分治樹中以該結點為根時,每個子樹中最長鏈的長度

所以我們可以得出每個分支區域樹中,B中的第一大元素和第二大元素的和即是答案

B由該結點為根的子樹中每個A的最大值組成

最後我們只需用樹鏈剖分求lca,並用差分求樹上任意兩點距離即可

三、時間複雜度&空間複雜度

時間複雜度為點分治的NlogN+堆的logN == O(Nlog2N)

空間複雜度:O(N)

  1 #include<bits/stdc++.h>
  2
#define INF 0x3f3f3f3f 3 #define MAXN 100010 4 using namespace std; 5 inline int read () 6 { 7 int w=1,s=0; 8 char ch=getchar (); 9 while (ch<'0'||ch>'9'){if (ch=='-') w=-1;ch=getchar ();} 10 while ('0'<=ch&&ch<='9') s=(s<<1)+(s<<3)+(ch^48
),ch=getchar (); 11 return s*w; 12 } 13 struct Heap{ 14 priority_queue<int>A,B;int size; 15 Heap(){size=0;} 16 void push (int x){A.push (x),size++;} 17 void pop (int x){B.push (x),size--;} 18 int top (){while (!B.empty ()&&A.top ()==B.top ()) A.pop (),B.pop ();return size?A.top ():-INF;} 19 int len () 20 { 21 if (size==0) return -1; 22 if (size==1) return 0; 23 int x=top ();pop (x);int y=top ();push (x); 24 return x+y; 25 } 26 void op (int x,int c){c?pop (x):push (x);} 27 }a[MAXN],b[MAXN],ans; 28 struct edge{ 29 int v,w,nxt; 30 }e[MAXN<<1]; 31 int n,q,cnt,root,sum,tot; 32 int head[MAXN],size[MAXN],maxp[MAXN],s[MAXN],col[MAXN]; 33 int Fa[MAXN],dep[MAXN],son[MAXN],dist[MAXN],top[MAXN]; 34 bool used[MAXN]; 35 char opt[MAXN]; 36 void add (int u,int v,int w) 37 { 38 e[++cnt].v=v,e[cnt].w=w,e[cnt].nxt=head[u],head[u]=cnt; 39 } 40 void dfs1 (int u,int fa) 41 { 42 Fa[u]=fa,size[u]=1,dep[u]=dep[fa]+1; 43 for (int i=head[u];i!=0;i=e[i].nxt) 44 if (e[i].v!=fa) 45 { 46 dist[e[i].v]=dist[u]+e[i].w; 47 dfs1 (e[i].v,u); 48 size[u]+=size[e[i].v]; 49 if (size[e[i].v]>size[son[u]]) son[u]=e[i].v; 50 } 51 } 52 void dfs2 (int u,int topf) 53 { 54 top[u]=topf; 55 if (son[u]) dfs2 (son[u],topf); 56 for (int i=head[u];i!=0;i=e[i].nxt) 57 if (e[i].v!=Fa[u]&&e[i].v!=son[u]) 58 dfs2 (e[i].v,e[i].v); 59 } 60 int lca (int x,int y) 61 { 62 while (dep[top[x]]!=dep[top[y]]) 63 { 64 if (dep[top[x]]<dep[top[y]]) swap (x,y); 65 x=Fa[top[x]]; 66 } 67 return dep[x]<dep[y]?x:y; 68 } 69 void getrt (int u,int fa) 70 { 71 size[u]=1,maxp[u]=0; 72 if (!col[u]) s[++tot]=u; 73 for (int i=head[u];i!=0;i=e[i].nxt) 74 if (e[i].v!=fa&&!used[e[i].v]) 75 { 76 getrt (e[i].v,u); 77 size[u]+=size[e[i].v]; 78 maxp[u]=max (maxp[u],size[e[i].v]); 79 } 80 maxp[u]=max (maxp[u],sum-size[u]); 81 if (maxp[u]<maxp[root]) root=u; 82 } 83 int f[MAXN]; 84 int getdis (int x,int y) 85 { 86 return dist[x]+dist[y]-(dist[lca (x,y)]<<1); 87 } 88 int divide (int u) 89 { 90 used[u]=1;if (!col[u]) b[u].push (0); 91 for (int i=1;i<=tot;i++) a[u].push (getdis (f[u],s[i])); 92 for (int i=head[u];i!=0;i=e[i].nxt) 93 if (!used[e[i].v]) 94 { 95 maxp[root=tot=0]=sum=size[e[i].v],getrt (e[i].v,0); 96 f[root]=u; 97 int child=divide (root); 98 b[u].push (a[child].top ()); 99 } 100 ans.push (b[u].len ()); 101 return u; 102 } 103 void modify (int x,int c) 104 { 105 int l1=b[x].len (),l2,s1,s2;b[x].op (0,c); 106 if (l1!=(l2=b[x].len ())) ans.pop (l1),ans.push (l2); 107 for (int u=x,fa=f[u];fa;fa=f[u=fa]) 108 { 109 s1=a[u].top (),a[u].op (getdis (fa,x),c),s2=a[u].top(); 110 if (s1!=s2) 111 { 112 l1=b[fa].len (); 113 if (s1!=-INF) b[fa].pop (s1); 114 if (s2!=-INF) b[fa].push (s2); 115 l2=b[fa].len (); 116 if (l1!=l2) ans.pop (l1),ans.push (l2); 117 } 118 } 119 } 120 int main() 121 { 122 n=read (); 123 for (int i=1;i<n;i++) 124 { 125 int u=read (),v=read (); 126 add (u,v,1);add (v,u,1); 127 } 128 dfs1 (1,0);dfs2 (1,1); 129 maxp[root]=sum=n,getrt (1,0); 130 divide (root); 131 q=read (); 132 while (q--) 133 { 134 scanf ("%s",opt+1); 135 if (opt[1]=='C') 136 { 137 int x=read ();col[x]^=1; 138 modify (x,col[x]); 139 } 140 else printf ("%d\n",ans.top ()); 141 } 142 return 0; 143 }