1. 程式人生 > >bzoj3488: [ONTAK2010]Highways 掃描線+樹狀陣列

bzoj3488: [ONTAK2010]Highways 掃描線+樹狀陣列

Description


給一棵n個點的樹以及m條額外的雙向邊
q次詢問,統計滿足以下條件的u到v的路徑:
恰經過一條額外的邊
不經過樹上u到v的路徑上的邊
n,m<=1e5,q<=5e5

Solution


非常眼熟。之前做過樹套樹的做法,現在記憶體卡得緊可以考慮掃描線的做法。
我們把一個矩形查詢看成四個字首和相加減的形式,然後掃描線+樹狀陣列維護字首和就可以了
這個getup好像每次都會寫錯。。

Code


#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <vector> #define rep(i,st,ed) for (int i=st;i<=ed;++i) #define lowbit(x) (x&-x) const int N=500005; struct edge {int y,next;} e[N*2]; struct quer {int x,y,v,id;} ; struct poin {int x,y;} ; int pos[N],size[N],bl[N],fa[N],dep[N]; int c[N],ls[N],ans[N],edCnt; int read() { int x=
0,v=1; char ch=getchar(); for (;ch<'0'||ch>'9';v=(ch=='-')?(-1):(v),ch=getchar()); for (;ch<='9'&&ch>='0';x=x*10+ch-'0',ch=getchar()); return x*v; } void add_edge(int x,int y) { e[++edCnt]=(edge) {y,ls[x]}; ls[x]=edCnt; e[++edCnt]=(edge) {x,ls[y]}; ls[y]=edCnt; } void dfs1(int now)
{ size[now]=1; for (int i=ls[now];i;i=e[i].next) { if (e[i].y==fa[now]) continue; fa[e[i].y]=now; dep[e[i].y]=dep[now]+1; dfs1(e[i].y); size[now]+=size[e[i].y]; } } void dfs2(int now,int up) { bl[now]=up; pos[now]=++pos[0]; int mx=0; for (int i=ls[now];i;i=e[i].next) { if (e[i].y!=fa[now]&&size[e[i].y]>size[mx]) mx=e[i].y; } if (!mx) return ; dfs2(mx,up); for (int i=ls[now];i;i=e[i].next) { if (e[i].y!=fa[now]&&e[i].y!=mx) dfs2(e[i].y,e[i].y); } } void add(int x,int v) { for (;x<=pos[0];x+=lowbit(x)) c[x]+=v; } int get(int x) { int res=0; for (;x;x-=lowbit(x)) res+=c[x]; return res; } int get_lca(int x,int y) { for (;bl[x]!=bl[y];x=fa[bl[x]]) { if (dep[bl[x]]<dep[bl[y]]) std:: swap(x,y); } return dep[x]<dep[y]?x:y; } int get_up(int x,int y) { if (fa[x]==y) return x; for (;bl[x]!=bl[y];x=fa[bl[x]]) { if (fa[bl[x]]==y) return bl[x]; } for (int i=ls[y];i;i=e[i].next) { if (e[i].y!=fa[y]&&bl[e[i].y]==bl[y]) return e[i].y; } } bool cmp1(poin a,poin b) { return a.x<b.x; } bool cmp2(quer a,quer b) { return a.x<b.x; } int main(void) { freopen("data.in","r",stdin); freopen("myp.out","w",stdout); int n=read(); rep(i,2,n) add_edge(read(),read()); dfs1(dep[1]=1); dfs2(1,1); std:: vector <poin> v; std:: vector <quer> q; int m=read(); rep(i,1,m) { int x=read(),y=read(); if (pos[x]>pos[y]) std:: swap(x,y); v.push_back((poin) {pos[x],pos[y]}); } int T=read(); rep(i,1,T) { int x=read(),y=read(); if (pos[x]>pos[y]) std:: swap(x,y); if (get_lca(x,y)==x) { int z=get_up(y,x); q.push_back((quer) {pos[z]-1,pos[y]+size[y]-1,1,i}); q.push_back((quer) {0,pos[y]+size[y]-1,-1,i}); q.push_back((quer) {pos[z]-1,pos[y]-1,-1,i}); q.push_back((quer) {0,pos[y]-1,1,i}); if (pos[y]+size[y]<=pos[0]) { q.push_back((quer) {pos[y]+size[y]-1,pos[0],1,i}); q.push_back((quer) {pos[y]-1,pos[0],-1,i}); q.push_back((quer) {pos[y]+size[y]-1,pos[z]+size[z]-1,-1,i}); q.push_back((quer) {pos[y]-1,pos[z]+size[z]-1,1,i}); } } else { q.push_back((quer) {pos[x]+size[x]-1,pos[y]+size[y]-1,1,i}); q.push_back((quer) {pos[x]-1,pos[y]+size[y]-1,-1,i}); q.push_back((quer) {pos[x]+size[x]-1,pos[y]-1,-1,i}); q.push_back((quer) {pos[x]-1,pos[y]-1,1,i}); } } std:: sort(v.begin(), v.end(),cmp1); std:: sort(q.begin(), q.end(),cmp2); for (int i=0,j=0;i<q.size();++i) { for (;j<v.size()&&v[j].x<=q[i].x;++j) { add(v[j].y,1); } ans[q[i].id]+=q[i].v*get(q[i].y); } rep(i,1,T) printf("%d\n", ans[i]+1); return 0; }