Gym - 102040F Path Intersection (树链剖分+线段树)
题意:给出棵树上的k条路径,求这些路径的公共点数量。
将每条路径上的点都打上标记,被标记过k次的点就是公共点了。由于公共点形成的区间是连续的,因此直接在线段树上暴搜即可在$O(logn)$求出一条链上公共点的数量。
怎样找被标记过k次的点呢?可以维护一个区间最大值mx和一个区间最小值mi,如果mx=mi=k说明这一段区间上的点全都为公共点。
清除标记加个线段树区间赋值即可(也可以把标记过的路径一条一条去掉)
1 #include<bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int N=1e4+10,mod=1e9+7; 5 int hd[N],n,ne,Q,m,fa[N],son[N],siz[N],dep[N],top[N],dfn[N],rnk[N],tot,ka; 6 int mx[N<<2],mi[N<<2],lza[N<<2],lzs[N<<2]; 7 struct E {int v,nxt;} e[N<<1]; 8 void addedge(int u,int v) {e[ne]= {v,hd[u]},hd[u]=ne++;} 9 void dfs1(int u,int f,int d) { 10 fa[u]=f,son[u]=0,siz[u]=1,dep[u]=d; 11 for(int i=hd[u]; ~i; i=e[i].nxt) { 12 int v=e[i].v; 13 if(v==fa[u])continue; 14 dfs1(v,u,d+1),siz[u]+=siz[v]; 15 if(siz[v]>siz[son[u]])son[u]=v; 16 } 17 } 18 void dfs2(int u,int tp) { 19 top[u]=tp,dfn[u]=++tot,rnk[dfn[u]]=u; 20 if(son[u])dfs2(son[u],top[u]); 21 for(int i=hd[u]; ~i; i=e[i].nxt) { 22 int v=e[i].v; 23 if(v==fa[u]||v==son[u])continue; 24 dfs2(v,v); 25 } 26 } 27 #define ls (u<<1) 28 #define rs (u<<1|1) 29 #define mid ((l+r)>>1) 30 void pu(int u) {mx[u]=max(mx[ls],mx[rs]),mi[u]=min(mi[ls],mi[rs]);} 31 void change(int u,int x,int f) { 32 if(f==0)lza[u]=0,lzs[u]=mx[u]=mi[u]=x; 33 else lza[u]+=x,mx[u]+=x,mi[u]+=x; 34 } 35 void pd(int u) { 36 if(~lzs[u])change(ls,lzs[u],0),change(rs,lzs[u],0),lzs[u]=-1; 37 if(lza[u])change(ls,lza[u],1),change(rs,lza[u],1),lza[u]=0; 38 } 39 void upd(int L,int R,int x,int f,int u=1,int l=1,int r=tot) { 40 if(l>=L&&r<=R) {change(u,x,f); return;} 41 if(l>R||r<L)return; 42 pd(u),upd(L,R,x,f,ls,l,mid),upd(L,R,x,f,rs,mid+1,r),pu(u); 43 } 44 int qry(int L,int R,int u=1,int l=1,int r=tot) { 45 if(l>=L&&r<=R&&mx[u]==m&&mi[u]==m)return r-l+1; 46 if(l>R||r<L||mx[u]!=m)return 0; 47 pd(u); 48 return qry(L,R,ls,l,mid)+qry(L,R,rs,mid+1,r); 49 } 50 void upd2(int u,int v) { 51 for(; top[u]!=top[v]; u=fa[top[u]]) { 52 if(dep[top[u]]<dep[top[v]])swap(u,v); 53 upd(dfn[top[u]],dfn[u],1,1); 54 } 55 if(dep[u]<dep[v])swap(u,v); 56 upd(dfn[v],dfn[u],1,1); 57 } 58 int qry2(int u,int v) { 59 int ret=0; 60 for(; top[u]!=top[v]; u=fa[top[u]]) { 61 if(dep[top[u]]<dep[top[v]])swap(u,v); 62 ret+=qry(dfn[top[u]],dfn[u]); 63 } 64 if(dep[u]<dep[v])swap(u,v); 65 ret+=qry(dfn[v],dfn[u]); 66 return ret; 67 } 68 int main() { 69 int T; 70 for(scanf("%d",&T); T--;) { 71 printf("Case %d:\n",++ka); 72 memset(hd,-1,sizeof hd),ne=tot=0; 73 scanf("%d",&n); 74 for(int i=1; i<n; ++i) { 75 int u,v; 76 scanf("%d%d",&u,&v); 77 addedge(u,v); 78 addedge(v,u); 79 } 80 dfs1(1,0,1),dfs2(1,1); 81 scanf("%d",&Q); 82 while(Q--) { 83 upd(1,tot,0,0); 84 scanf("%d",&m); 85 for(int i=0; i<m; ++i) { 86 int u,v; 87 scanf("%d%d",&u,&v); 88 upd2(u,v); 89 if(i==m-1)printf("%d\n",qry2(u,v)); 90 } 91 } 92 } 93 }