bzoj3488: [ONTAK2010]Highways 扫描线+树状数组

版权声明:虽然是个蒟蒻但是转载还是要说一声的哟 https://blog.csdn.net/jpwang8/article/details/84841057

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;
}

猜你喜欢

转载自blog.csdn.net/jpwang8/article/details/84841057