图论:动态点分治
一般如果需要大规模处理树上路径,点分治是一个不错的选择
在解决树上路径满足某种属性的数量统计方面有着很大的作用
点分治的核心抄dalao的两句话:
1.对于端点是自己子树上的任意一条路径,它要么经过自己,要么在自己的某个子树中 2.获取树的重心来把树的深度从O(n)变到O(logn)
然后稍微说一说动态点分治,在原来点分治的基础上,添加一个fa数组
我们相当于通过fa数组重建了一棵点分树。这棵点分树的深度是最多logn的
在点分治中,每个点都会作为重心,但它们作为重心的时候管辖的范围不同
对于某个点,我们维护的是这个点作为重心时所管辖的那一坨树的信息
树上的动态点分治就相当于序列上的线段树??
可以理解为序列的区间问题用线段树维护,树的区间问题用点分树来维护?
所以我们要修改一个点的点权的时候,我们就直接在点分树暴跳父亲,然后因为点分树的性质从而保证复杂度是O(nlogn)
这里很像线段树的点修改
那么点分治的过程就相当于建树的过程喽?
据说可以用线段树维护括号序列来解决这个问题?周末之前看来学不完了,先挖个坑
然后说一下BZOJ1095的题面
给定一棵树,每个节点要么是黑色,要么是白色,能执行两个操作:
把某一个点取反色,返回距离最远的黑色点对
把每次分治的重心连成一棵树,树的深度是logn,每次修改一个结点只影响它到树根的一条链
黄学长说实现起来要用三层堆?
C.每个重心存所有子树到其距离
B.每个重心存各个子树最大值,即子结点堆C的最大值
A.全局一个堆,维护答案最大值,存每个堆B的最大值和次大值之和
为了赶进度,最近的更博只能抄代码了,实在惭愧。
1 #include<set> 2 #include<map> 3 #include<ctime> 4 #include<queue> 5 #include<cmath> 6 #include<cstdio> 7 #include<vector> 8 #include<cstring> 9 #include<cstdlib> 10 #include<iostream> 11 #include<algorithm> 12 #define inf 1000000000 13 #define mod 1000000007 14 #define pa pair<int,int> 15 #define ll long long 16 using namespace std; 17 inline int read() 18 { 19 int x=0,f=1;char ch=getchar(); 20 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 21 while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();} 22 return x*f; 23 } 24 int bin[20],Log[200005]; 25 int n,m,G,cnt,dfn,sum,tot; 26 int size[100005],f[100005],deep[100005],last[100005]; 27 int mn[18][200005],pos[100005],fa[100005]; 28 bool vis[100005],clo[100005]; 29 struct edge{ 30 int to,next; 31 }e[200005]; 32 void insert(int u,int v) 33 { 34 e[++cnt]=(edge){v,last[u]};last[u]=cnt; 35 e[++cnt]=(edge){u,last[v]};last[v]=cnt; 36 } 37 struct heap{ 38 priority_queue<int> A,B; 39 void push(int x){ 40 A.push(x); 41 } 42 void erase(int x){ 43 B.push(x); 44 } 45 void pop(){ 46 while(B.size()&&A.top()==B.top()) 47 A.pop(),B.pop(); 48 A.pop(); 49 } 50 int top(){ 51 while(B.size()&&A.top()==B.top()) 52 A.pop(),B.pop(); 53 if(!A.size())return 0; 54 return A.top(); 55 } 56 int size(){ 57 return A.size()-B.size(); 58 } 59 int stop(){ 60 if(size()<2)return 0; 61 int x=top();pop(); 62 int y=top();push(x); 63 return y; 64 } 65 }A,B[100005],C[100005]; 66 void dfs(int x,int fa) 67 { 68 mn[0][++dfn]=deep[x]; 69 pos[x]=dfn; 70 for(int i=last[x];i;i=e[i].next) 71 if(e[i].to!=fa) 72 { 73 deep[e[i].to]=deep[x]+1; 74 dfs(e[i].to,x); 75 mn[0][++dfn]=deep[x]; 76 } 77 } 78 void getrt(int x,int fa) 79 { 80 size[x]=1;f[x]=0; 81 for(int i=last[x];i;i=e[i].next) 82 if(e[i].to!=fa&&!vis[e[i].to]) 83 { 84 getrt(e[i].to,x); 85 size[x]+=size[e[i].to]; 86 f[x]=max(f[x],size[e[i].to]); 87 } 88 f[x]=max(f[x],sum-size[x]); 89 if(f[x]<f[G])G=x; 90 } 91 void divi(int x,int f) 92 { 93 fa[x]=f;vis[x]=1; 94 for(int i=last[x];i;i=e[i].next) 95 if(!vis[e[i].to]) 96 { 97 sum=size[e[i].to];G=0; 98 getrt(e[i].to,x); 99 divi(G,x); 100 } 101 } 102 int rmq(int x,int y) 103 { 104 x=pos[x];y=pos[y]; 105 if(y<x)swap(x,y); 106 int t=Log[y-x+1]; 107 return min(mn[t][x],mn[t][y-bin[t]+1]); 108 } 109 int dis(int x,int y) 110 { 111 return deep[x]+deep[y]-2*rmq(x,y); 112 } 113 void turn_off(int u,int v) 114 { 115 if(u==v) 116 { 117 B[u].push(0); 118 if(B[u].size()==2)A.push(B[u].top()); 119 } 120 if(!fa[u])return; 121 int f=fa[u],D=dis(f,v),tmp=C[u].top(); 122 C[u].push(D); 123 if(D>tmp) 124 { 125 int mx=B[f].top()+B[f].stop(),size=B[f].size(); 126 if(tmp)B[f].erase(tmp); 127 B[f].push(D); 128 int now=B[f].top()+B[f].stop(); 129 if(now>mx) 130 { 131 if(size>=2)A.erase(mx); 132 if(B[f].size()>=2)A.push(now); 133 } 134 } 135 turn_off(f,v); 136 } 137 void turn_on(int u,int v) 138 { 139 if(u==v) 140 { 141 if(B[u].size()==2)A.erase(B[u].top()); 142 B[u].erase(0); 143 } 144 if(!fa[u])return; 145 int f=fa[u],D=dis(f,v),tmp=C[u].top(); 146 C[u].erase(D); 147 if(D==tmp) 148 { 149 int mx=B[f].top()+B[f].stop(),size=B[f].size(); 150 B[f].erase(D); 151 if(C[u].top())B[f].push(C[u].top()); 152 int now=B[f].top()+B[f].stop(); 153 if(now<mx) 154 { 155 if(size>=2)A.erase(mx); 156 if(B[f].size()>=2)A.push(now); 157 } 158 } 159 turn_on(f,v); 160 } 161 int main() 162 { 163 bin[0]=1;for(int i=1;i<20;i++)bin[i]=bin[i-1]<<1; 164 Log[0]=-1;for(int i=1;i<=200000;i++)Log[i]=Log[i>>1]+1; 165 n=read(); 166 for(int i=1;i<n;i++) 167 { 168 int u=read(),v=read(); 169 insert(u,v); 170 } 171 dfs(1,0); 172 for(int i=1;i<=Log[dfn];i++) 173 for(int j=1;j<=dfn;j++) 174 if(j+bin[i]-1<=dfn) 175 mn[i][j]=min(mn[i-1][j],mn[i-1][j+bin[i-1]]); 176 G=0;f[0]=inf;sum=n; 177 getrt(1,0);divi(G,0); 178 for(int i=1;i<=n;i++)C[i].push(0); 179 for(int i=1;i<=n;i++)clo[i]=1; 180 for(int i=1;i<=n;i++) 181 { 182 turn_off(i,i); 183 tot++; 184 } 185 char ch[2]; 186 m=read(); 187 while(m--) 188 { 189 scanf("%s",ch+1); 190 if(ch[1]=='G') 191 { 192 if(tot<=1)printf("%d\n",tot-1); 193 else printf("%d\n",A.top()); 194 } 195 else 196 { 197 int x=read(); 198 if(clo[x])turn_on(x,x),tot--; 199 else turn_off(x,x),tot++; 200 clo[x]^=1; 201 } 202 } 203 return 0; 204 }