jzoj6276. 【noip提高组模拟1】树

Time Limits: 1000 ms

Memory Limits: 524288 KB

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

满足条件的路径为<1,2>,<1,3>,<1,4>,<1,5>,<1,6>,<1,7>,<2,4>,<2,5>,< 3,6>,< 3,7>,<4,5>。

赛时

一看到这么多的√,心想——一定可以水到巨多的分数。
看到m=1,不是送的吗?直接拿总答案减去不合法的即可。
看到菊花图,不是送的吗?如果不合法的限制一个是叶子,一个是根,则把叶子删掉。
剩下的-1即可。
看到链的情况,发现不会。
然后又发现n和m那么小,于是稳拿70.
最后发现,我™把调试程序交上去了!!!(调试输出的东西没删)
然后还没发现到限制重复。
10分妙啊♂

题解

部分分上面说过了,除了链的情况。
我们发现,对于链,直观的想法——设限制为x,y,y是x的祖宗。
那么y的祖先与x的儿子两两匹配都是不行的(显然)。
那么我们弄出一个二维平面,x轴表示从第i个点出发,y轴表示抵达第j个点。
这样就变成了在二维平面内有很多矩形,这些矩形内的点不能选。
这玩意不是扫描线吗?

即可解决,拿到90分的好成绩。

等等,既然我们想到这里了,100分不就很显然了吗?
我们对于数弄出dfn序,那么我们可以很轻松地处理出每个点对应的子树。
在二维平面内搞搞即可。
但是!如果y是x祖宗这类情况怎么办?
很简单,求出一个y到x简单路径中距离y最近的点z。
然后由于是dfn序,那么对于y以外的点就是除了z子树范围的其他点。
分成两个区间即可。

标程

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
using namespace std;

struct node
{
	int a,b,x,y;
};
struct node1
{
	int l,r,x,k;
};
struct node2
{
	int a,lazy;
};

int q,x,y,tot,lx,ly,num,op,p,now;
long long ans,size[100011],n;
int tov[200011],next[200011],last[200011],fa[100011],qx[100001],qy[100001],dep[100011],rd[100011],ii[100011],st[100001],en[100001],f[100001][18];
bool bz[201],kk[100001];
node1 lis[800001];
node gin[800001];
node2 tree[800001];

void joinit(int p)
{
	op++;lis[op].l=gin[p].x;lis[op].r=gin[p].y;lis[op].x=gin[p].a;lis[op].k=1;
	op++;lis[op].l=gin[p].x;lis[op].r=gin[p].y;lis[op].x=gin[p].b+1;lis[op].k=-1;
	op++;lis[op].l=gin[p].a;lis[op].r=gin[p].b;lis[op].x=gin[p].x;lis[op].k=1;
	op++;lis[op].l=gin[p].a;lis[op].r=gin[p].b;lis[op].x=gin[p].y+1;lis[op].k=-1;
}

void make_tree(int k,int l,int r)
{
	tree[k].a=r-l+1;
	tree[k].lazy=0;
	if (l!=r)
	{
		int mid=(l+r)/2;
		make_tree(k*2,l,mid);
		make_tree(k*2+1,mid+1,r);
	}
}

void update(int x,int l,int r)
{
	if (tree[x].lazy==0)
	{
		tree[x].a=tree[x*2].a+tree[x*2+1].a;
		if (l==r) tree[x].a=1;
	}
	else
	{
		tree[x].a=0;
	}
}

void change(int x,int l,int r,int st,int en,int gb)
{
	if (l<=en && r>=st)
	{
		if (l>=st && r<=en)
		{
			tree[x].lazy=tree[x].lazy+=gb;
			update(x,l,r);
		}
		else
		{
			int m=(l+r)/2;
			change(x*2,l,m,st,en,gb);
			change(x*2+1,m+1,r,st,en,gb);
			update(x,l,r);
		}
	}
	else return;
}

void insert(int x,int y)
{
	tot++;
	tov[tot]=y;
	next[tot]=last[x];
	last[x]=tot;
}

void dfs(int x)
{
	num++;
	st[x]=num;
	size[x]=1;
	f[x][0]=fa[x];
	for (ii[x]=0;ii[x]<=17;ii[x]++)
	{
		if (f[x][ii[x]]!=0 && f[f[x][ii[x]]][ii[x]]!=0)
		{
			f[x][ii[x]+1]=f[f[x][ii[x]]][ii[x]];
		}
		else break;
	}
	
	ii[x]=last[x];
	while (ii[x]>0)
	{
		if (tov[ii[x]]!=fa[x])
		{
			fa[tov[ii[x]]]=x;
			dep[tov[ii[x]]]=dep[x]+1;
			dfs(tov[ii[x]]);
			size[x]+=size[tov[ii[x]]];
		}
		ii[x]=next[ii[x]];
	} 
	en[x]=num;
}

void qsort(int l,int r)
{
	int i=l;int j=r;
	int m=qx[(i+j)/2];
	int m1=qy[(i+j)/2];
	while (i<=j)
	{
		while ((qx[i]<m) || (qx[i]==m && qy[i]>m1)) i++;
		while ((qx[j]>m) || (qx[j]==m && qy[j]<m1)) j--;
		if (i<=j)
		{
			swap(qx[i],qx[j]);
			swap(qy[i],qy[j]);
			i++;j--;
		}
	}
	if (l<j) qsort(l,j);
	if (r>i) qsort(i,r); 
}

void qsort1(int l,int r)
{
	int i=l;int j=r;
	int m=lis[(i+j)/2].x;
	while (i<=j)
	{
		while (lis[i].x<m) i++;
		while (lis[j].x>m) j--;
		if (i<=j)
		{
			swap(lis[i],lis[j]);
			i++;j--;
		}
	}
	if (l<j) qsort1(l,j);
	if (r>i) qsort1(i,r); 
}

int get_lca(int x,int y)
{
	if (dep[x]<dep[y])
	{
		swap(x,y);	
	}
	int i=17;
	while (i>=0)
	{
		if (dep[f[x][i]]>dep[y])
		{
			x=f[x][i];
		}
		i--;
	}
	if (x==y) return y;
	else
	{
		for (int i=17;i>=0;i--);
		if (f[x][i]!=f[y][i])
		{
			x=f[x][i];
			y=f[y][i];
		}
		return f[x][0];
	}
}

int main()
{
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	scanf("%lld%d",&n,&q);
	for (int i=1;i<n;i++)
	{
		scanf("%d%d",&x,&y);
		insert(x,y);
		insert(y,x);
		rd[x]++;rd[y]++;
	}
	dfs(1);
	for (int i=1;i<=q;i++)
	{
		scanf("%d%d",&qx[i],&qy[i]);
	}
	{
		int p=0;
		for (int i=1;i<=q;i++)
		{
			if (qx[i]!=qx[i-1] || qy[i]!=qy[i-1])
			{
				if (dep[qx[i]]<=dep[qy[i]]) swap(qx[i],qy[i]);
				int lca=get_lca(qx[i],qy[i]);
				if (qx[i]!=lca && qy[i]!=lca)
				{
					p++;gin[p].a=st[qx[i]];gin[p].x=st[qy[i]];gin[p].b=en[qx[i]];gin[p].y=en[qy[i]];
//					printf("%d %d %d %d\n",gin[p].a,gin[p].b,gin[p].x,gin[p].y);
					joinit(p);
				}
				else
				{
					int k=qx[i];
					int j=17;
					while (j>=0)
					{
						if (dep[f[k][j]]>dep[qy[i]]) k=f[k][j];
						j--;
					}
					p++;gin[p].a=st[qx[i]];gin[p].x=1;gin[p].b=en[qx[i]];gin[p].y=st[k]-1;
//					printf("%d %d %d %d\n",gin[p].a,gin[p].b,gin[p].x,gin[p].y);
					joinit(p);
					//if (en[k]!=n)
					{
						p++;gin[p].a=st[qx[i]];gin[p].x=en[k]+1;gin[p].b=en[qx[i]];gin[p].y=n;
//						printf("%d %d %d %d\n",gin[p].a,gin[p].b,gin[p].x,gin[p].y);
						joinit(p);
					}
				}
			}
		}
	}
	make_tree(1,1,n);
	qsort1(1,op);
	ans=0;
	now=1;
	for (int i=1;i<=n;i++)
	{
		while (now<=op && lis[now].x==i)
		{
			change(1,1,n,lis[now].l,lis[now].r,lis[now].k);
			now++;
		}
		ans+=tree[1].a;
	}
	ans-=n;
	printf("%lld\n",ans/2);
}

posted @ 2019-08-08 22:07  RainbowCrown  阅读(244)  评论(0编辑  收藏  举报