codeforces1486 F. Pairs of Paths(倍增+树上数数)
F. Pairs of Paths
syksykCCC題解
iamhpp題解
首先說明,下面圖片來自第一篇博客,下面代碼照抄第二篇博客
對沒有啥是自己寫的(因為我太菜~~
從上圖可以看出兩條鏈只有一個交點可能有兩種情況
- 交點是兩條鏈的LCA
- 交點是一條鏈的LCA而不是另一條
這兩種情況的公共點就是:交點一定是一條鏈的LCA,因此我們從LCA考慮計數
對于第一種情況,如果存在一條鏈x0?y0x_0\leadsto y_0x0??y0?與x?yx\leadsto yx?y滿足條件,一定有LCA(x0,y0)=LCA(x,y)LCA(x_0,y_0)=LCA(x,y)LCA(x0?,y0?)=LCA(x,y)并且x,y,x0,y0x,y,x_0,y_0x,y,x0?,y0?分別處在lcalcalca的4棵子樹中。
首先每次考慮相同LCA的鏈,因而第一個條件滿足,第二個條件我們每條鏈記錄xxx處于lca的aaa子樹中,而yyy處于lca的bbb子樹中,也就是如果lca是xxx的kkk級祖先,那么aaa是xxx的k?1k-1k?1級祖先(倍增跳一下即可)鏈的情況,把aaa設為?1-1?1
有了上面信息,我們考慮一條鏈x?yx\leadsto yx?y,那些和它LCA相同的鏈x0?y0x_0\leadsto y_0x0??y0?對答案有貢獻當且僅當a,b,a0,b0a,b,a_0,b_0a,b,a0?,b0?是4個不同的值,這可以用容斥原理計算
對于第二種情況,對于上圖考慮A1?A2A_1\leadsto A_2A1??A2?這條鏈存在多少條像B1?B2B_1\leadsto B_2B1??B2?的鏈,首先不難發現B1?B2B_1\leadsto B_2B1??B2?的LCA的深度一定嚴格小于A1?A2A_1\leadsto A_2A1??A2?的LCA,也就是如果想要和A1?A2A_1\leadsto A_2A1??A2?配對對答案產生貢獻,那么其鏈的LCA深度一定較小,因此考慮按照LCA深度排序依次處理。
每次只需要統計LCA子樹中有多少像B1B_1B1?這樣的點(在LCA的子樹中并且不與A1,A2A_1,A_2A1?,A2?在同一子樹)找個支持單點修改子樹查詢的數據結構即可,這里用dfs序+樹狀數組統計。
#define IO ios::sync_with_stdio(false);cin.tie();cout.tie(0) #pragma GCC optimize(2) #include<map> #include<vector> #include<cstring> #include<iostream> #include<algorithm> using namespace std; using ll=long long; using pii=pair<int,int>; constexpr int N=300010; int h[N],e[2*N],ne[2*N],idx; void add(int a,int b){e[idx]=b,ne[idx]=h[a],h[a]=idx++;} int n,m; int dep[N],fa[N][21],dfn[N],sz[N],timestamp; void dfs(int u) {dfn[u]=++timestamp;sz[u]=1;for(int i=h[u];i!=-1;i=ne[i]){int v=e[i];if(v==fa[u][0])continue;dep[v]=dep[u]+1;fa[v][0]=u;for(int k=1;k<=20;k++)fa[v][k]=fa[fa[v][k-1]][k-1];dfs(v);sz[u]+=sz[v];} } int lca(int u,int v) {if(dep[u]<dep[v]) swap(u,v);for(int k=20;k>=0;k--)if(dep[fa[u][k]]>=dep[v]) u=fa[u][k];if(u==v) return u;for(int k=20;k>=0;k--)if(fa[u][k]!=fa[v][k]) u=fa[u][k],v=fa[v][k];return fa[u][0]; } int up(int u,int d)// 從u向上跳d步 {if(d<=0) return u;for(int k=20;k>=0;k--)if(d>>k&1) u=fa[u][k];return u; } struct node {int x,y,a,b,lca; }q[N]; int fw[N]; int lowbit(int x){return x&-x;} void update(int k,int x){for(;k<=n;k+=lowbit(k)) fw[k]+=x;} int query(int k){int res=0;for(;k;k-=lowbit(k)) res+=fw[k];return res;}int main() {IO;cin>>n;memset(h,-1,sizeof h);for(int i=1;i<n;i++){int u,v;cin>>u>>v;add(u,v),add(v,u);}dep[1]=1;dfs(1);cin>>m;for(int i=1;i<=m;i++){int x,y;cin>>x>>y;int anc=lca(x,y);int a=up(x,dep[x]-dep[anc]-1),b=up(y,dep[y]-dep[anc]-1);if(a==anc) a=-1;if(b==anc) b=-1;if(a>b) swap(a,b),swap(x,y);q[i]={x,y,a,b,anc};}sort(q+1,q+1+m,[](const node &i,const node&j){if(dep[i.lca]!=dep[j.lca]) return dep[i.lca]<dep[j.lca];return i.lca<j.lca;});ll ans1=0,ans2=0;for(int i=1;i<=m;i++){map<pii,int> f;map<int,int> cnt;int j=i;while(j<=m&&q[j].lca==q[i].lca) j++;//lca相同的一起統計for(int k=i;k<j;k++){int x=q[k].x,y=q[k].y,a=q[k].a,b=q[k].b,anc=q[k].lca;ans1+=k-i-cnt[a]-cnt[b]+f[{a,b}];if(a!=-1) cnt[a]++;if(b!=-1) cnt[b]++;if(a!=-1&&b!=-1) f[{a,b}]++;}i=j-1;}for(int i=1;i<=m;i++){int j=i;while(j<=m&&dep[q[j].lca]==dep[q[i].lca]) j++;//深度相同的一起統計for(int k=i;k<j;k++){int x=q[k].x,y=q[k].y,a=q[k].a,b=q[k].b,anc=q[k].lca;ans2+=query(dfn[anc]+sz[anc]-1)-query(dfn[anc]-1);if(a!=-1) ans2-=query(dfn[a]+sz[a]-1)-query(dfn[a]-1);if(b!=-1) ans2-=query(dfn[b]+sz[b]-1)-query(dfn[b]-1);}for(int k=i;k<j;k++) update(dfn[q[k].x],1),update(dfn[q[k].y],1);i=j-1;}cout<<ans1+ans2<<'\n'; }總結
以上是生活随笔為你收集整理的codeforces1486 F. Pairs of Paths(倍增+树上数数)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 为什么说中国现在非常缺石油
- 下一篇: LOJ dfs序1234