BZOJ 4285 使者 (CDQ分治+dfs序)
题目大意:给你一棵树,有三种操作,在两个点之间连一个传送门,拆毁一个已有的传送门,询问两个点之间的合法路径数量。一条合法路径满足 1.经过且仅经过一个传送门 2.不经过起点终点简单路径上的任何一条边
这模型转化好神啊
首先把树拍成$dfs$序
问题是在树上,我们把$x,y$这条链拎出来摊平,那么链上每个点都挂了一些子树。
容易发现合法路径数=连接以$x,y$为根的子树的传送门数量
而无根树并没有“子树”这一概念,所以先随便挑一个根跑出来dfs序。
发现“子树”的$dfs$序一定是一个或两个连续的区间,我们分$x,y$是否为$lca$讨论一下就可以了
然后把问题放到二维坐标系上。
问题转化成,动态在一个二维平面内加入/删除一个点,以及查询矩形内点的数量
由于存在修改操作,需要再加上一维。那么整个问题变成了一个三维偏序问题。用$CDQ$分治+树状数组即可
1 #include <cmath> 2 #include <cstdio> 3 #include <cstring> 4 #include <algorithm> 5 #define N1 100005 6 #define M1 500005 7 #define ll long long 8 #define uint unsigned int 9 using namespace std; 10 11 template <typename _T> void read(_T &ret) 12 { 13 ret=0; _T fh=1; char c=getchar(); 14 while(c<'0'||c>'9'){ if(c=='-') fh=-1; c=getchar(); } 15 while(c>='0'&&c<='9'){ ret=ret*10+c-'0'; c=getchar(); } 16 ret=ret*fh; 17 } 18 19 struct Edge{ 20 int to[N1*2],nxt[N1*2],head[N1],cte; 21 void ae(int u,int v) 22 { cte++; to[cte]=v; nxt[cte]=head[u]; head[u]=cte; } 23 }e; 24 25 int n; 26 27 namespace Tree{ 28 int dep[N1],fa[N1],ff[N1][19],st[N1],ed[N1],ord[N1],cur; 29 void dfs1(int x) 30 { 31 int j,v; ff[x][0]=x; st[x]=++cur; ord[cur]=x;//sz[x]=1; 32 for(j=e.head[x];j;j=e.nxt[j]) 33 { 34 v=e.to[j]; if(v==fa[x]) continue; 35 fa[v]=x; ff[v][1]=x; dep[v]=dep[x]+1; 36 dfs1(v); 37 } 38 ed[x]=cur; 39 } 40 void init() 41 { 42 dep[1]=1; dfs1(1); 43 int i,j; 44 for(j=2;j<=18;j++) 45 for(i=1;i<=n;i++) 46 ff[i][j]=ff[ ff[i][j-1] ][j-1]; 47 } 48 int LCA(int x,int y) 49 { 50 int i,ans=0; 51 if(dep[x]<dep[y]) swap(x,y); 52 for(i=18;i>=0;i--) 53 if(dep[ff[x][i]]>=dep[y]) x=ff[x][i]; 54 if(x==y) return x; 55 for(i=18;i>=0;i--) 56 if(ff[x][i]==ff[y][i]) ans=ff[x][i]; 57 else x=ff[x][i], y=ff[y][i]; 58 return ans; 59 } 60 int LCB(int x,int D) 61 { 62 int i; 63 for(i=18;i>=0;i--) 64 if(dep[ff[x][i]]>=D) x=ff[x][i]; 65 return x; 66 } 67 }; 68 69 struct BIT{ 70 int sum[N1]; 71 void upd(int x,int w) 72 { 73 if(!x) return; int i; 74 for(i=x;i<=n;i+=(i&(-i))) 75 sum[i]+=w; 76 } 77 int query(int x) 78 { 79 int ans=0,i; 80 for(i=x;i>0;i-=(i&(-i))) 81 ans+=sum[i]; 82 return ans; 83 } 84 void clr(int x) 85 { 86 int i; 87 for(i=x;i<=n;i+=(i&(-i))) 88 sum[i]=0; 89 } 90 }bit; 91 92 struct OP{ int x,y,t,type,f; }op[M1],tmp[M1]; 93 int cmp2(OP &s1,OP &s2) 94 { 95 if(s1.x!=s2.x) return s1.x<s2.x; 96 if(s1.y!=s2.y) return s1.y<s2.y; 97 return s1.type<s2.type; 98 } 99 int ans[N1],que[M1],isquery[N1],tl; 100 101 void CDQ(int L,int R) 102 { 103 if(L==R) return; 104 int M=(L+R)>>1,i,j,cnt=0; 105 CDQ(L,M); CDQ(M+1,R); 106 for(i=L,j=M+1;i<=M&&j<=R;) 107 { 108 if(cmp2(op[i],op[j])){ 109 if(!op[i].type) bit.upd(op[i].y,op[i].f), que[++tl]=op[i].y; 110 tmp[++cnt]=op[i]; i++; 111 }else{ 112 if(op[j].type) ans[op[j].t]+=op[j].f*bit.query(op[j].y); 113 tmp[++cnt]=op[j]; j++; 114 } 115 } 116 while(i<=M){ tmp[++cnt]=op[i]; i++; } 117 while(j<=R){ tmp[++cnt]=op[j]; if(op[j].type) ans[op[j].t]+=op[j].f*bit.query(op[j].y); j++; } 118 for(i=L;i<=R;i++) op[i]=tmp[i-L+1]; 119 while(tl){ bit.clr(que[tl]); tl--; } 120 } 121 122 int m,Q1,Q2; 123 using Tree::st; using Tree::ed; using Tree::dep; using Tree::LCA; using Tree::LCB; 124 125 int main() 126 { 127 scanf("%d",&n); 128 int i,j,x,y,z,F,q,fl; 129 for(i=1;i<n;i++) read(x), read(y), e.ae(x,y), e.ae(y,x); 130 Tree::init(); 131 read(Q1); 132 for(q=1;q<=Q1;q++) 133 { 134 read(x); read(y); 135 op[++m]=(OP){st[x],st[y],0,0,1}; op[++m]=(OP){st[y],st[x],0,0,1}; 136 } 137 read(Q2); 138 for(q=1;q<=Q2;q++) { 139 140 read(fl); read(x); read(y); 141 if(fl==1){ 142 op[++m]=(OP){st[x],st[y],q,0,1}; op[++m]=(OP){st[y],st[x],q,0,1}; 143 }else if(fl==2){ 144 op[++m]=(OP){st[x],st[y],q,0,-1}; op[++m]=(OP){st[y],st[x],q,0,-1}; 145 }else if(fl==3){ 146 F=LCA(x,y); isquery[q]=1; 147 if(x==F||y==F){ 148 if(x==F) swap(x,y); z=LCB(x,dep[F]+1); 149 op[++m]=(OP){ed[x],st[z]-1,q,1,1}; //op[++m]=(OP){ed[x],0,q,1,-1}; 150 op[++m]=(OP){st[x]-1,st[z]-1,q,1,-1}; //op[++m]=(OP){st[x]-1,0,q,1,1}; 151 op[++m]=(OP){ed[x],n,q,1,1}; op[++m]=(OP){ed[x],ed[z],q,1,-1}; 152 op[++m]=(OP){st[x]-1,n,q,1,-1}; op[++m]=(OP){st[x]-1,ed[z],q,1,1}; 153 }else{ 154 op[++m]=(OP){ed[x],ed[y],q,1,1}; op[++m]=(OP){ed[x],st[y]-1,q,1,-1}; 155 op[++m]=(OP){st[x]-1,ed[y],q,1,-1}; op[++m]=(OP){st[x]-1,st[y]-1,q,1,1}; 156 } 157 } 158 159 } 160 161 CDQ(1,m); 162 for(i=1;i<=Q2;i++) if(isquery[i]) 163 printf("%d\n",ans[i]); 164 return 0; 165 }