标签:head ima getchar alt else 距离 \n 修改 树链剖分
动态点分治
先看一道题目 [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 }
标签:head ima getchar alt else 距离 \n 修改 树链剖分
原文地址:https://www.cnblogs.com/PaulShi/p/10057768.html