QTREE4
QTREE4
点分治
题目链接:https://www.luogu.org/problemnew/show/P4115
参考:http://www.cnblogs.com/yanshannan/p/9411098.html
首先观察此题每条边的长度-1000<=w<=1000
而当0<=w<=1000的时候会有一个更优的nlogn解法
线段树维护树的直径
怎么维护?
有一个结论:
一颗树内,某些点构成的点集 形成的一个新树,该树的直径端点为x,y;
现在新加入一个点z,形成新的点集构成的新树的直径端点为(x,y)或(x,z)或(y,z);
于是用线段树维护一下就好,合并时用线段树两个儿子代表的树直径端点更新即可
lca用dfs序+st表,单次查询O1
线段树维护的代码
1 #include<iostream> 2 #include<cstdio> 3 using namespace std; 4 const int M=100009; 5 int n,m,num=0,id=0,sum; 6 int head[M],fir[M],L[M<<1],pw[23],val[M],f[M<<1][23],dep[M]; 7 struct P{int to,ne,w;}e[M<<1]; 8 int ls[M<<2],rs[M<<2],len[M<<2]; 9 bool vis[M]; 10 int read(){ 11 int rex=0,f=1;char ch=getchar(); 12 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 13 while(ch>='0'&&ch<='9'){rex=rex*10+ch-'0';ch=getchar();} 14 return rex*f; 15 } 16 void dfs(int u,int fa,int w){ 17 f[fir[u]=++id][0]=u;val[u]=w;dep[u]=dep[fa]+1; 18 for(int i=head[u];i;i=e[i].ne){ 19 int v=e[i].to; 20 if(v!=fa){dfs(v,u,w+e[i].w);f[++id][0]=u;} 21 } 22 } 23 int Min(int x,int y){ 24 return dep[x]<dep[y]?x:y; 25 } 26 int ask(int l,int r){ 27 l=fir[l],r=fir[r]; 28 if(l>r)swap(l,r); 29 int k=L[r-l+1]; 30 return Min(f[l][k],f[r-pw[k]+1][k]); 31 } 32 int dis(int u,int v){ 33 return val[u]+val[v]-2*val[ask(u,v)]; 34 } 35 void merge(int a,int b,int c,int dist=0){ 36 if(ls[a]==0||ls[b]==0){ 37 ls[c]=ls[a]+ls[b]; 38 rs[c]=rs[a]+rs[b]; 39 len[c]=len[a]+len[b]; 40 return; 41 } 42 if(len[a]<len[b])swap(a,b); 43 ls[c]=ls[a],rs[c]=rs[a],len[c]=len[a]; 44 dist=dis(ls[a],ls[b]); 45 if(dist>len[c]){len[c]=dist;ls[c]=ls[a];rs[c]=ls[b];} 46 dist=dis(ls[a],rs[b]); 47 if(dist>len[c]){len[c]=dist;ls[c]=ls[a];rs[c]=rs[b];} 48 dist=dis(rs[a],ls[b]); 49 if(dist>len[c]){len[c]=dist;ls[c]=rs[a];rs[c]=ls[b];} 50 dist=dis(rs[a],rs[b]); 51 if(dist>len[c]){len[c]=dist;ls[c]=rs[a];rs[c]=rs[b];} 52 } 53 void build(int now,int l,int r){ 54 if(l==r){ 55 ls[now]=rs[now]=l; 56 len[now]=0; 57 return; 58 } 59 int mid=(l+r)>>1; 60 build(now<<1,l,mid); 61 build(now<<1|1,mid+1,r); 62 merge(now<<1,now<<1|1,now); 63 } 64 void update(int now,int l,int r,int x){ 65 if(l==r){ 66 if(vis[x])ls[now]=rs[now]=len[now]=0; 67 else ls[now]=rs[now]=x,len[now]=0; 68 return; 69 } 70 int mid=(l+r)>>1; 71 if(x<=mid)update(now<<1,l,mid,x); 72 else update(now<<1|1,mid+1,r,x); 73 merge(now<<1,now<<1|1,now); 74 } 75 int main(){ 76 n=read(); 77 for(int i=1,u,v,w;i<n;++i){ 78 u=read(),v=read(),w=read(); 79 e[++num]=(P){v,head[u],w};head[u]=num; 80 e[++num]=(P){u,head[v],w};head[v]=num; 81 } 82 dfs(1,0,0);pw[0]=1;L[1]=0; 83 for(int i=1;i<=19;++i)pw[i]=pw[i-1]<<1; 84 for(int i=2;i<=id;++i)L[i]=L[i>>1]+1; 85 for(int j=1;j<=19;++j){ 86 for(int i=1;i+pw[j]-1<=id;++i){ 87 f[i][j]=Min(f[i][j-1],f[i+pw[j-1]][j-1]); 88 } 89 } 90 build(1,1,n); 91 m=read();sum=n; 92 for(int i=1;i<=m;++i){ 93 char c[5]; 94 scanf("%s",c); 95 if(c[0]=='C'){ 96 int x=read(); 97 vis[x]^=1; 98 update(1,1,n,x); 99 if(vis[x])sum--; 100 else sum++; 101 } 102 else { 103 if(sum==0)printf("They have disappeared.\n"); 104 else printf("%d\n",len[1]); 105 } 106 } 107 return 0; 108 }
当然此题的w是可以<0的,所以树直径的结论就不满足了
此时我们就需要用到另外一种算法:动态点分治(O(n log ^2 n))
就是对分治树上的每个点开2个堆
1:此子树白点到他父节点的距离大根堆 a
2:此节点的每个儿子子树中的白点到该节点的最大值组成的大根堆 b
1用来更新2,此时经过某个重心u的 两个白点最大距离 可以为 b[u]大根堆的 最大值和次大值之和
最后再总的维护一个答案堆 ans 即可
更新答案就分治树上往上走,顺便更新下经过节点的堆和答案堆即可
这三种堆需要满足一种操作,pop(x);
可以开个结构题,里面2个堆,插入堆和删除堆
取堆顶时,插入堆堆顶和删除堆堆顶相同时,2个堆同时pop(),如果不同就return 插入堆.top();
代码
1 #include<iostream> 2 #include<cstdio> 3 #include<queue> 4 using namespace std; 5 const int M=100009; 6 int n,m,num=0,id=0,sum=0; 7 int head[M]; 8 int pw[23],L[M<<1],fir[M],val[M],dep[M],f[M<<1][23]; 9 struct P{int to,ne,w;}e[M<<1]; 10 int minn,rt,size,siz[M],ft[M]; 11 bool vis[M],co[M]; 12 struct Queue{ 13 priority_queue<int>s,t;int sz; 14 inline void push(int x){s.push(x);sz++;} 15 inline void pop(int x){t.push(x);sz--;} 16 inline int top(){ 17 if(sz==0)return -1e9; 18 while(!t.empty()&&s.top()==t.top())s.pop(),t.pop(); 19 return s.top(); 20 } 21 inline int len(){ 22 if(sz<2)return 0; 23 int x=top();pop(x); 24 int y=top();push(x); 25 return max(0,x+y); 26 } 27 inline void del(int k,int x){k==0?push(x):pop(x);} 28 }a[M],b[M],ans; 29 inline int read(){ 30 int rex=0,f=1;char ch=getchar(); 31 while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();} 32 while(ch>='0'&&ch<='9'){rex=rex*10+ch-'0';ch=getchar();} 33 return rex*f; 34 } 35 void dfs(int u,int fa,int w){ 36 f[fir[u]=++id][0]=u;val[u]=w;dep[u]=dep[fa]+1; 37 for(int i=head[u];i;i=e[i].ne){ 38 int v=e[i].to; 39 if(v!=fa){dfs(v,u,w+e[i].w);f[++id][0]=u;} 40 } 41 } 42 inline int Min(int x,int y){ 43 return dep[x]<dep[y]?x:y; 44 } 45 inline int ask(int l,int r){ 46 l=fir[l],r=fir[r]; 47 if(l>r)swap(l,r); 48 int k=L[r-l+1]; 49 return Min(f[l][k],f[r-pw[k]+1][k]); 50 } 51 inline int dis(int u,int v){ 52 return val[u]+val[v]-2*val[ask(u,v)]; 53 } 54 void getrt(int u,int fa){ 55 int ma=0;siz[u]=1; 56 for(int i=head[u];i;i=e[i].ne){ 57 int v=e[i].to;if(v==fa||vis[v])continue; 58 getrt(v,u);siz[u]+=siz[v];ma=max(ma,siz[v]); 59 } 60 ma=max(ma,size-siz[u]); 61 if(minn>ma){minn=ma,rt=u;} 62 } 63 void DFS(int u,int fa,int now){ 64 a[now].push(dis(ft[now],u)); 65 for(int i=head[u];i;i=e[i].ne){ 66 int v=e[i].to; 67 if(v!=fa&&!vis[v])DFS(v,u,now); 68 } 69 } 70 void work(int u){ 71 if(ft[u])DFS(u,0,u);vis[u]=1;b[u].push(0); 72 for(int i=head[u];i;i=e[i].ne){ 73 int v=e[i].to;if(vis[v])continue; 74 minn=1e9,size=siz[u]; 75 getrt(v,0);ft[rt]=u; 76 int la=rt; 77 work(rt);b[u].push(a[la].top()); 78 } 79 ans.push(b[u].len()); 80 } 81 inline void change(int u){ 82 ans.pop(b[u].len()); 83 b[u].del(co[u],0); 84 ans.push(b[u].len()); 85 for(int i=u;ft[i];i=ft[i]){ 86 int x=a[i].top(); 87 a[i].del(co[u],dis(ft[i],u)); 88 int y=a[i].top(); 89 if(x==y)continue; 90 ans.pop(b[ft[i]].len()); 91 b[ft[i]].pop(x); 92 b[ft[i]].push(y); 93 ans.push(b[ft[i]].len()); 94 } 95 } 96 int main(){ 97 n=read(); 98 for(int i=1,u,v,w;i<n;++i){ 99 u=read(),v=read(),w=read(); 100 e[++num]=(P){v,head[u],w};head[u]=num; 101 e[++num]=(P){u,head[v],w};head[v]=num; 102 } 103 dfs(1,0,0);pw[0]=1;L[1]=0; 104 for(int i=1;i<=19;++i)pw[i]=pw[i-1]<<1; 105 for(int i=2;i<=id;++i)L[i]=L[i>>1]+1; 106 for(int j=1;j<=19;++j){ 107 for(int i=1;i+pw[j]-1<=id;++i){ 108 f[i][j]=Min(f[i][j-1],f[i+pw[j-1]][j-1]); 109 } 110 } 111 minn=1e9,size=n; 112 getrt(1,0); 113 work(rt); 114 m=read();sum=n; 115 for(int i=1;i<=m;++i){ 116 char c[5]; 117 scanf("%s",c); 118 if(c[0]=='C'){ 119 int x=read(); 120 co[x]^=1; 121 change(x); 122 sum+=co[x]?-1:1; 123 } 124 else { 125 sum==0?printf("They have disappeared.\n") 126 :printf("%d\n",ans.top()); 127 } 128 } 129 return 0; 130 }