1. 程式人生 > >【2018/11/05測試T3】相交

【2018/11/05測試T3】相交

【題目】

傳送門


【分析】

一道不錯的題

首先,要知道一個東西,即若兩條路徑相交,則一條路徑的 lcalca 必然在另一條路徑上

我們每加入一條邊,都計算一下之前的邊加上它對答案的貢獻

現在假設加 (a,b)(a,b) 條邊,具體有一下幾種情況:

統計 (a,b)(a,b) 這條路徑上的 lcalca 個數:

大致長這樣:
在這裡插入圖片描述
我們給每個點一個點權,代表從這個點到根路徑上的 lcalca 數量(記為 numinum_i

那麼最後的答案顯然是 numa+numb2numlcanum_a+num_b-2*num_{lca}

2numlca

每次做完更新的時候,要在 lcalca 的子樹內的 num+1num+1,代表它們到根的 lcalca 數量多了一個(就是 lcalca

怎麼維護這個 numnum 呢?可以用一個區間修改單點查詢的樹狀陣列來維護(畢竟程式碼量小,常數也小)

統計穿過 (a,b)(a,b)lcalca 的路徑數量:

大概長這樣:
在這裡插入圖片描述
利用類似於樹上差分的思想,在兩個端點加一,在 lcalca 處減二

這樣做之後,把一個子樹內的值統計出來,就是穿過 lcalca 的路徑的數量

因為,如果一條路徑在 (a,b)(a,b)

,b) 內部,或者在外面(就是不相交的情況),那麼它的值就會被抵消掉(1+121+1-2

而只有這種一個點在內部,lcalca 和另一個點在外部的情況(也就是合法情況)才會被統計到

那麼這個又怎麼維護呢?用一個單點修改區間查詢的樹狀陣列就行了

一些要注意的細節:
  1. 兩個樹狀陣列維護的是不一樣的東西,不要弄混了
  2. 注意 lcalca 重複的情況要單獨計算,不然會重複(以上兩種方法都會算一次)

【程式碼】

#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 1000005
#define M 2000005 #define lowbit(x) x&-x using namespace std; int n,m,t,tot; int first[N],v[M],nxt[M]; int num[N],bit1[N],bit2[N]; int dep[N],size[N],pos[N],fa[N][25]; void add(int x,int y) { t++; nxt[t]=first[x]; first[x]=t; v[t]=y; } void dfs(int x) { int i,j; size[x]=1,pos[x]=++tot; for(i=1;i<=20;++i) fa[x][i]=fa[fa[x][i-1]][i-1]; for(i=first[x];i;i=nxt[i]) { j=v[i]; if(j!=fa[x][0]) { fa[j][0]=x; dep[j]=dep[x]+1; dfs(j); size[x]+=size[j]; } } } int Lca(int x,int y) { int i; if(dep[x]<dep[y]) swap(x,y); for(i=20;~i;--i) if(dep[fa[x][i]]>=dep[y]) x=fa[x][i]; if(x==y) return x; for(i=20;~i;--i) if(fa[x][i]!=fa[y][i]) x=fa[x][i],y=fa[y][i]; return fa[x][0]; } void modify(int *bit,int i,int x) { while(i<=n) { bit[i]+=x; i+=lowbit(i); } } int query(int *bit,int i) { int ans=0; while(i) { ans+=bit[i]; i-=lowbit(i); } return ans; } int main() { // freopen("access.in","r",stdin); // freopen("access.out","w",stdout); int x,y,i; scanf("%d%d",&n,&m); for(i=1;i<n;++i) { scanf("%d%d",&x,&y); add(x,y),add(y,x); } dep[1]=1,dfs(1); long long ans=0; for(i=1;i<=m;++i) { scanf("%d%d",&x,&y); int lca=Lca(x,y); ans+=num[lca],num[lca]++; ans+=query(bit1,pos[x])+query(bit1,pos[y])-2*query(bit1,pos[lca]); ans+=query(bit2,pos[lca]+size[lca]-1)-query(bit2,pos[lca]-1); modify(bit1,pos[lca],1); modify(bit1,pos[lca]+size[lca],-1); modify(bit2,pos[x],1); modify(bit2,pos[y],1); modify(bit2,pos[lca],-2); } printf("%lld",ans); // fclose(stdin); // fclose(stdout); return 0; }