1. 程式人生 > >動態點分治及其應用

動態點分治及其應用

答案 ctime || 白色 urn 原來 解決 -s 操作

一般如果需要大規模處理樹上路徑,點分治是一個不錯的選擇

在解決樹上路徑滿足某種屬性的數量統計方面有著很大的作用

點分治的核心抄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 }

動態點分治及其應用