[Codeforces348E][bzoj4342][DP]Pilgrims

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/Rose_max/article/details/82961880

Description

在很久以前有一片土地被称为 Dudeland。Dudeland 包含 n 个城镇, 它们用 n − 1
条双向道路连接起来。这些城镇通过道路可以两两互达。这 里有 m 个修道院坐落在 m 个不同的城镇。每个修道院有一个教徒。
在一年之始,每个教徒会选择离他最远的一个修道院。如果有多个, 他会把所有的都列入清单。在 “BigLebowskiday”
里,每个教徒会随机选 择一个清单里的城镇开始走去。 Walter 讨厌教徒。他想尽可能的通过阻止他们的行程来让尽可能多的
人不开心。他计划摧毁一个没有修道院的城镇。一个教徒如果在他的清单 里没有任何一个城镇能去,他就会不开心。 你需要求出 Walter
最多能让几个教徒不开心。除此之外,你还要计算 他有多少种方法。

Input

第一行包含两个整数 n,m,满足 3 ≤ n ≤ 10^5, 2 ≤ m<n。 接下来一行,有 m
个互不相同的整数,他们代表了有修道院的城镇的 编号。 接下来 n − 1 行,每行三个整数 ai,bi,ci,表示 ai,bi
之间有一条边权 为 ci 的边。(1 ≤ ai,bi ≤ n,ai = bi,ci ≤ 1000)

Output

输出两个数:最多能让几个教徒不开心,以及有多少种方式达到这种效果。

Sample Input

8 5

7 2 5 4 8

1 2 1

2 3 2

扫描二维码关注公众号,回复: 3554299 查看本文章

1 4 1

4 5 2

1 6 1

6 7 8

6 8 10

Sample Output

5 1

前言

bzoj的数据真是辣鸡怎么写都能过…
写错了一堆重要地方都过了什么辣鸡数据…
哦CF的好像也有点问题…
BTW Claris的代码似乎被我拍出了一个错…
放一下数据
我最强```
INPUT:
15 12
1 9 13 12 11 10 5 4 7 14 3 6
2 1 2
3 2 1
4 1 2
5 4 1
6 3 1
7 1 1
8 5 1
9 3 1
10 5 1
11 1 1
12 4 1
13 3 1
14 1 1
15 5 1

OUTPUT:
8 1


题解

> 我要当~~第一篇~~正经题解
> 先考虑辣鸡做法
> 对每个修道院找到所有距离他最长的修道院
> 能割断他们的联系的显然是这些修道院的LCA到当前修道院的链上所有点
> 如果子树内有并且子树外也有显然这个修道院不能做贡献
> 树上差分一下最后扫一遍就行了
> 考虑如何优化这个做法
> 对于每个点,我们维护一些值
> 他到子树内某个点的最大值与次大值,同时强制让这两个点不能在同一棵子树
> 维护down表示这两个点的编号
> 维护count表示最大值和次大值出现了多少次
> 考虑如何找LCA的过程
> 如果这个点的不同子树最大值出现了多于一次,那么他们被割断的LCA至少是当前点
> 否则可以直接继承最大值所在的子树的割断点编号
> 对于子树外的,每次往下的时候把贡献加上
> 处理子树外贡献的时候维护最长链以及割断编号
> 这个基础上用树上差分扫一遍就ok了
> ~~我怎么写的这么长啊~~

```cpp
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<queue>
#include<vector>
#include<ctime>
#include<map>
#define LL long long
#define mp(x,y) make_pair(x,y)
using namespace std;
inline int read()
{
	int f=1,x=0;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
	return x*f;
}
inline void write(int x)
{
	if(x<0)putchar('-'),x=-x;
	if(x>9)write(x/10);
	putchar(x%10+'0');
}
inline void print(int x){write(x);printf(" ");}
const int inf=(1<<31-1);
struct node{int x,y,c,next;}a[210000];int len,last[110000];
void ins(int x,int y,int c){len++;a[len].x=x;a[len].y=y;a[len].c=c;a[len].next=last[x];last[x]=len;}
struct pt{int mx[3],ct,ct1,down,down1;}w[110000];
int fa[110000][25],dep[110000],bin[25];
int in[110000],ot[110000],dfn;
void pre_tree_node(int x)
{
	in[x]=++dfn;
	for(int i=1;bin[i]<=dep[x];i++)fa[x][i]=fa[fa[x][i-1]][i-1];
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		if(y!=fa[x][0])
		{
			fa[y][0]=x;dep[y]=dep[x]+1;
			pre_tree_node(y);
		}
	}
	ot[x]=dfn;
}
int lca(int x,int y)
{
	if(dep[x]<dep[y])swap(x,y);
	for(int i=20;i>=0;i--)if(bin[i]<=dep[x]&&dep[fa[x][i]]>=dep[y])x=fa[x][i];
	if(x==y)return x;
	for(int i=20;i>=0;i--)if(bin[i]<=dep[x]&&fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
	return fa[x][0];
}
void updata(int u,int v,int c)
{
	if(w[v].mx[0]==-inf)return ;
	int dis=w[v].mx[0]+c;
	if(w[u].mx[0]<dis)
	{
		swap(w[u].mx[2],w[u].mx[1]);swap(w[u].mx[1],w[u].mx[0]);swap(w[u].down1,w[u].down);swap(w[u].ct,w[u].ct1);
		w[u].mx[0]=dis;w[u].ct=1;if(w[v].ct>1)w[u].down=v;else w[u].down=w[v].down;
	}
	else if(w[u].mx[0]==dis)
	{
		swap(w[u].mx[2],w[u].mx[1]);swap(w[u].mx[1],w[u].mx[0]);swap(w[u].down1,w[u].down);w[u].ct1=w[u].ct;
		w[u].mx[0]=dis;w[u].ct++;w[u].ct1++;if(w[v].ct>1)w[u].down=v;else w[u].down=w[v].down;
	}
	else if(w[u].mx[1]<dis)
	{
		swap(w[u].mx[1],w[u].mx[2]),w[u].mx[1]=dis,w[u].ct1=1;
		if(w[v].ct>1)w[u].down1=v;else w[u].down1=w[v].down;
	}
	else if(w[u].mx[1]==dis)
	{
		swap(w[u].mx[1],w[u].mx[2]);w[u].mx[1]=dis;
		if(w[v].ct>1)w[u].down1=v;else w[u].down1=w[v].down;
		w[u].ct1++;
	}
	else if(w[u].mx[2]<dis)w[u].mx[2]=dis;
}
bool v[110000];
void dp1(int x)
{
	w[x].mx[0]=w[x].mx[1]=w[x].mx[2]=-inf;
	if(v[x])w[x].mx[0]=0,w[x].down=x;
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		if(y!=fa[x][0])dp1(y),updata(x,y,a[k].c);
	}
}
int sum[110000];
void dp2(int x,int cal,int pos)//上面最长链权值 位置 
{
	if(w[x].mx[0]>cal&&v[x])
	{
		if(w[x].ct<=1)
		{
			int LA=lca(x,w[x].down);
			sum[w[x].down]++;sum[x]++;sum[LA]--;sum[fa[LA][0]]--;
		//	printf("%d %d\n",x,w[x].down);
		}
	}
	else if(w[x].mx[0]<cal&&v[x])
	{
		int LA=lca(x,pos);
		sum[pos]++;sum[x]++;sum[LA]--;sum[fa[LA][0]]--;
	//	printf("%d %d\n",x,pos);
	}
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		if(y!=fa[x][0])
		{
			int dis=w[y].mx[0]+a[k].c,pa,sss;
			if(dis==w[x].mx[0])
			{
				pa=w[x].mx[1]+a[k].c;
				if(w[x].ct1>2&&w[x].mx[1]==w[x].mx[0])sss=x;
				if(w[x].ct1==2&&w[x].mx[1]==w[x].mx[0])
				{
					if(in[w[x].down1]>=in[y]&&in[w[x].down1]<=ot[y])sss=w[x].down;
					else sss=w[x].down1;
				}
				if(w[x].ct1>=2&&w[x].mx[1]!=w[x].mx[0])sss=x;
				else 
				{
					if(in[w[x].down1]>=in[y]&&in[w[x].down1]<=ot[y])sss=w[x].down;
					else sss=w[x].down1;
				}
			}
			else
			{
				pa=w[x].mx[0]+a[k].c;
				sss=w[x].ct>1?x:w[x].down;
			}
			if(pa==cal+a[k].c)dp2(y,cal+a[k].c,x);
			else if(pa<cal+a[k].c)dp2(y,cal+a[k].c,pos);
			else
			{
				if(dis==w[x].mx[0])dp2(y,pa,sss);
				else dp2(y,pa,sss);
			}
		}
	}
}
void merge(int x)
{
	for(int k=last[x];k;k=a[k].next)
	{
		int y=a[k].y;
		if(y!=fa[x][0])merge(y),sum[x]+=sum[y];
	}
}
int n,m;
int main()
{
	bin[0]=1;for(int i=1;i<=20;i++)bin[i]=bin[i-1]<<1;
	n=read();m=read();
	memset(v,false,sizeof(v));
	for(int i=1;i<=m;i++)v[read()]=true;
	for(int i=1;i<n;i++)
	{
		int x=read(),y=read(),c=read();	
		ins(x,y,c);ins(y,x,c);
	}
	pre_tree_node(1);
	dp1(1);
	dp2(1,v[1]?0:-inf,0);
//	for(int i=1;i<=n;i++)printf("ID %d:   %d %d %d %d %d %d %d\n",i,w[i].mx[0],w[i].mx[1],w[i].mx[2],w[i].down,w[i].down1,w[i].ct,w[i].ct1);
	merge(1);
	int s=0,ans=0;
	for(int i=1;i<=n;i++)if(!v[i])s=max(s,sum[i]);
	for(int i=1;i<=n;i++)if(sum[i]==s&&!v[i])ans++;
	printf("%d %d\n",s,ans);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/Rose_max/article/details/82961880