bzoj3488: [ONTAK2010]Highways 掃描線+樹狀陣列
阿新 • • 發佈:2018-12-23
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;
}