[NOIP模擬]相遇/行程的交集
阿新 • • 發佈:2020-07-27
Description
豪哥生活在一個 n 個點的樹形城市裡面,每一天都要走來走去。雖然走的是比較的 多,但是豪哥在這個城市裡面的朋友並不是很多。 當某一天,猴哥給他展現了一下大佬風範之後,豪哥決定要獲得一些交往機會來提升交 往能力。豪哥現在已經物色上了一條友,打算和它(豪哥並不讓吃瓜群眾知道性別)交 往。豪哥現在 spy 了一下這個人的所有行程起點和終點,豪哥打算從終點開始走到起點與 其相遇。但是豪哥是想找話題的,他想知道以前有多少次行程和此次行程是有交集的,這 樣豪哥就可以搭上話了。這個路徑與之前路徑的有交集數量作為豪哥此次的交往機會。 但是豪哥急著要做交往準備,所以算什麼交往機會的小事情就交給你了。
Solution
如果兩條路徑有交集,只可能是以下兩種情況:
- 此條路徑的lca在之前某條路徑上
- 之前某條路徑的lca在此條路徑上
這兩個情況有交集——兩條路徑的lca重合,所以統計答案時可以這樣操作:
- 更新答案:
- 在A樹中將此條路徑的lca的子樹全部+1
- 在B樹中將此條路徑兩端點+1,lca-2
- 統計答案:
- 統計在A樹中兩端點到根的路徑減去lca到根的路徑上lca數量
- 統計在B樹中lca的子樹
- lca重合的情況特判
可以用樹狀陣列處理
#include<iostream> #include<cstdio> using namespace相遇std; int n,m,fa[200005][25],st[200005],ed[200005],cnt,dep[200005],sum[200005],ans,head[200005],tot; struct Edge { int to,nxt; }edge[400005]; int lowbit(int x) { return x&-x; } struct Tree { int tree[200005]; void add(int pos,int v) { while(pos<=n) { tree[pos]+=v; pos+=lowbit(pos); } } int query(int pos) { int ret=0; while(pos) { ret+=tree[pos]; pos-=lowbit(pos); } return ret; } }tr1,tr2; inline int read() { int f=1,w=0; char ch=0; while(ch<'0'||ch>'9') { if(ch=='-') f=-1; ch=getchar(); } while(ch>='0'&&ch<='9') { w=(w<<1)+(w<<3)+ch-'0'; ch=getchar(); } return f*w; } void dfs(int k,int f) { fa[k][0]=f; st[k]=++cnt; dep[k]=dep[f]+1; for(int i=1;i<=20;i++) { fa[k][i]=fa[fa[k][i-1]][i-1]; } for(int i=head[k];i;i=edge[i].nxt) { int v=edge[i].to; if(v==f) { continue; } dfs(v,k); } ed[k]=cnt; } int lca(int x,int y) { if(dep[x]<dep[y]) { swap(x,y); } for(int i=20;i>=0;i--) { if(dep[fa[x][i]]>=dep[y]) { x=fa[x][i]; } } if(x==y) { return x; } for(int i=20;i>=0;i--) { if(fa[x][i]!=fa[y][i]) { x=fa[x][i]; y=fa[y][i]; } } return fa[x][0]; } int main() { n=read(); for(int i=1;i<n;i++) { int u=read(),v=read(); edge[++tot]=(Edge){v,head[u]}; head[u]=tot; edge[++tot]=(Edge){u,head[v]}; head[v]=tot; } dfs(1,0); m=read(); for(int i=1;i<=m;i++) { int u=read(),v=read(),x=lca(u,v); printf("%d\n",tr1.query(st[v])+tr1.query(st[u])-2*tr1.query(st[x])+tr2.query(ed[x])-tr2.query(st[x]-1)+sum[x]); sum[x]++; tr1.add(st[x],1); tr1.add(ed[x]+1,-1); tr2.add(st[u],1); tr2.add(st[v],1); tr2.add(st[x],-2); } return 0; }