JZOJ 6276. 【noip提高组模拟1】树(DFS序+扫描线)

JZOJ 6276. 【noip提高组模拟1】树

题目

Description

有一棵n个节点的无根树,给出其中的m对点对<x,y>。问有多少条树上的简单路径<u,v>满足该路径上不存在任何一对给出的点对<x,y>。
这里我们认为路径<u,v>和<v,u>是相同的。并且对于题目中给出的点对<x,y>满足x!=y,对于你要计数的路径<u,v>满足u!=v(即单点不算答案)。

Input

第一行两个正整数n,m。
接下来n-1行每行两个正整数u,v描述树上的一条边。
接下来m行每行两个正整数x,y描述一对给出的点对。
(注意,这里我们不保证同样的点对<x,y>不会重复出现)

Output

一行一个整数,表示满足要求的树上简单路径的条数。

Sample Input

8 3
1 2
1 3
4 8
2 4
2 5
3 6
3 7
2 3
4 8
6 7

Sample Output

11

Data Constraint

在这里插入图片描述

Hint

满足条件的路径为 &lt; 1 , 2 &gt; , &lt; 1 , 3 &gt; , &lt; 1 , 4 &gt; , &lt; 1 , 5 &gt; , &lt; 1 , 6 &gt; , &lt; 1 , 7 &gt; , &lt; 2 , 4 &gt; , &lt; 2 , 5 &gt; , &lt; 3 , 6 &gt; , &lt; 3 , 7 &gt; , &lt; 4 , 5 &gt; &lt;1,2&gt;,&lt;1,3&gt;,&lt;1,4&gt;,&lt;1,5&gt;,&lt;1,6&gt;,&lt;1,7&gt;,&lt;2,4&gt;,&lt;2,5&gt;,&lt;3,6&gt;,&lt;3,7&gt;,&lt;4,5&gt; <1,2><1,3><1,4><1,5><1,6><1,7><2,4><2,5><3,6><3,7><4,5>

题解

  • 观察题目,易得答案为总路径条数(不重复)减去不符合条件的路径条数,
  • 对于一个 &lt; x , y &gt; &lt;x,y&gt; <x,y>,令其 d e e p [ x ] ≥ d e e p [ y ] deep[x]≥deep[y] deep[x]deep[y]
  • 情况一:若 y y y x x x的祖先,则 x x x子树内的所有点 n n n个点中除了 y y y的子树以外的所有点之间相互的路径都是不合法的,因为路径必定经过 x x x y y y
  • 情况二:若 x x x y y y没有祖先关系,则 x x x子树内的所有点 y y y子树内的所有点之间相互的路径都是不合法的,它们必定经过 x x x y y y
  • 但对于不同的 &lt; x , y &gt; &lt;x,y&gt; <x,y>,这些路径会有重复,所以不能单纯地直接计算,那怎么办呢?
  • 先把 n n n个点的 D F S DFS DFS序求出来,把不能互相连通的两个区间分别作为矩形的横纵坐标位置,将其覆盖在坐标系中,
  • [ x 1 , x 2 ] [x1,x2] [x1,x2]这是一个区间)与 [ y 1 , y 2 ] [y1,y2] [y1,y2]不能相互到达,那么在 x 1 x1 x1处, [ y 1 , y 2 ] [y1,y2] [y1,y2]区间打上 + 1 +1 +1标记,在 x 2 + 1 x2+1 x2+1处, [ y 1 , y 2 ] [y1,y2] [y1,y2]区间打上 − 1 -1 1标记,
  • 那么对应的区间怎么表示呢?
  • 情况一:分两个区间,情况二:分一个区间。(请自行思考,用 d f n [ ] dfn[] dfn[] s i z e [ ] size[] size[]
  • 然后扫描线从左往右扫,用线段树区间修改维护,因为每个加入的区间,后面必定会对应的删除,所以这是标记不下传的区间修改
  • 记录 s [ v ] s[v] s[v]表示线段树上当前区间整段被覆盖的次数, f [ v ] f[v] f[v]为整个区间未被覆盖的总长度,
  • 每次 + 1 +1 +1时, s [ v ] + + s[v]++ s[v]++ f [ v ] = 0 f[v]=0 f[v]=0
  • 每次 − 1 -1 1时, s [ v ] − − s[v]-- s[v],当 s [ v ] = 0 s[v]=0 s[v]=0时, f [ v ] = f [ l ] + f [ r ] f[v]=f[l]+f[r] f[v]=f[l]+f[r](由左右子树更新自己的值),
  • 同时回溯时更新 f [ v ] = f [ l ] + f [ r ] f[v]=f[l]+f[r] f[v]=f[l]+f[r]
  • a n s ans ans每次累加 [ i + 1 , n ] [i+1,n] [i+1,n]的答案(这样才不会重复)。

代码

#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define LL long long
#define N 100010
int last[N],next[N*2],to[N*2],len=0;
int dfn[N],si[N],dp[N],f[N][20];
int qs=0,bz[N*4];
LL g[N*4],s=0;
struct node
{
	int x,l,r,c;
}q[N*4];
void add(int x,int y)
{
	to[++len]=y;
	next[len]=last[x];
	last[x]=len;
}
void dfs(int k,int fa)
{
	dp[k]=dp[fa]+1,si[k]=1,dfn[k]=++dfn[0];
	f[k][0]=fa;
	for(int i=1;i<20;i++) f[k][i]=f[f[k][i-1]][i-1];
	for(int i=last[k];i;i=next[i]) if(to[i]!=fa)
	{
		dfs(to[i],k);
		si[k]+=si[to[i]];
	}
}
void insert(int x,int xx,int y,int yy)
{
	if(x>xx) return;
	if(y>yy) return;
	if(y<x) swap(x,y),swap(xx,yy);
	q[++qs].x=x,q[qs].l=y,q[qs].r=yy,q[qs].c=1;
	q[++qs].x=xx+1,q[qs].l=y,q[qs].r=yy,q[qs].c=-1;
}
int cmd(node x,node y) 
{
	return x.x<y.x;
}
void make(int v,int l,int r,int x,int y,int c)
{
	if(l==x&&r==y)
	{
		bz[v]+=c;
		if(bz[v]) g[v]=r-l+1;
		if(!bz[v])
		{
			if(l!=r) g[v]=g[v*2]+g[v*2+1]; else g[v]=0;	
		}
	}
	else
	{
		int mid=(l+r)/2;
		if(y<=mid) make(v*2,l,mid,x,y,c);
		else if(x>mid) make(v*2+1,mid+1,r,x,y,c);
		else make(v*2,l,mid,x,mid,c),make(v*2+1,mid+1,r,mid+1,y,c);
		if(!bz[v]) g[v]=g[v*2]+g[v*2+1];
	}
}
void find(int v,int l,int r,int x,int y)
{
	if(l==x&&r==y)
	{
		s+=r-l+1-g[v];
	}
	else
	{
		int mid=(l+r)/2;
		if(y<=mid) find(v*2,l,mid,x,y);
		else if(x>mid) find(v*2+1,mid+1,r,x,y);
		else find(v*2,l,mid,x,mid),find(v*2+1,mid+1,r,mid+1,y);
	}
}
int main()
{
	int n,m,i,j,x,y;
	scanf("%d%d",&n,&m);
	for(i=1;i<n;i++) 
	{
		scanf("%d%d",&x,&y);
		add(x,y),add(y,x);
	}
	dfs(1,0);
	for(i=1;i<=m;i++)
	{
		scanf("%d%d",&x,&y);
		if(dp[x]<dp[y]) swap(x,y);
		int tx=x;
		if(dp[x]==dp[y])
		{
			insert(dfn[x],dfn[x]+si[x]-1,dfn[y],dfn[y]+si[y]-1);
			continue;
		}
		for(j=19;j>=0;j--) if(dp[x]-(1<<j)>dp[y]) x=f[x][j];
		int tp=x;
		x=f[x][0];
		if(x==y)
		{
			x=tx;
			insert(dfn[x],dfn[x]+si[x]-1,1,dfn[tp]-1);
			insert(dfn[x],dfn[x]+si[x]-1,dfn[tp]+si[tp],n);
		}
		else
		{
			x=tx;
			insert(dfn[x],dfn[x]+si[x]-1,dfn[y],dfn[y]+si[y]-1);
		}
	}
	sort(q+1,q+qs+1,cmd);
	j=1;
	for(i=1;i<n;i++)
	{
		while(j<=qs&&q[j].x==i)
		{
			make(1,1,n,q[j].l,q[j].r,q[j].c);
			j++;
		}
		find(1,1,n,i+1,n);
	}
	printf("%lld
",s);
	return 0;
}
哈哈哈哈哈哈哈哈哈哈
原文地址:https://www.cnblogs.com/LZA119/p/13910068.html