poj3417

HL_ZZP發表於2024-07-13

poj3417

題目其實很簡單,如果知道樹上差分是什麼基本就是秒了。
首先題面所說的,有\(n-1\)條邊,保證兩點之間只有一條簡單路徑,顯然是樹。
剩下的邊就是讓這個樹產生環的非樹邊。題面要求刪除兩條邊,使之分為兩部分,假如沒有環狀的結構,也就是沒有那些非樹邊,就只需要隨便刪除一條邊就可以達成要求。題面要求這兩條邊必須是一條樹上的邊和非樹邊。其實就已經挺明顯的了,我們對每一個非樹邊,讓這個非樹邊所連結的兩個點對應的樹上的簡單路徑上的邊全部+1,到最後,如果某一個邊只被覆蓋了一次,那麼切斷他就一定能夠找到其它的非樹邊,使得這兩個邊被切斷能夠達成題目要求。

所以只需要對每個非樹邊,把他們對應的樹上的邊全部\(+1\),最後再統計所有隻被覆蓋過一次,或者一次都沒被覆蓋的樹邊即可。

樹上差分也是比較簡單的,就是對於一個簡單路徑,如果要給他們之間的簡單路徑\(+1\),就是給這兩個節點\(+1\),然後給他們的lca\(-2\)
統計的時候就是直接統計對於每個節點的子樹的權值和\(F[x]\),這就是這個點和它父親節點之間的樹邊上的值。

然後就沒了。

為什麼re
為什麼。
我找不到錯啊啊啊啊啊啊啊啊

#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <math.h>
#include <string.h>
#define ll long long
using namespace std;
inline ll read(){
	ll a=0,b=1;char c=getchar();
	for(;c<'0'||c>'9';c=getchar())if(c=='-')b=-1;
	for(;c>='0'&&c<='9';c=getchar())a=a*10+c-'0';
	return a*b;
}
struct edge
{
	ll next,to;
}e1[400001];
ll head1[400001],tot1,tot2;
ll dep[400001][22],f[400001][22],val[400001];
ll n,m;
inline void add1(ll i,ll j)
{
	e1[++tot1].next=head1[i];
	e1[tot1].to=j;
	head1[i]=tot1;
}
void dfs(ll x,ll fa,ll now)
{
	dep[x][0]=now-1;f[x][0]=fa;
	for(ll i=head1[x];i!=0;i=e1[i].next)
	{
		ll u=e1[i].to;
		if(u==fa)continue;
		dfs(u,x,now+1);
	}
}
inline ll ask_lca(ll x,ll y)
{
	if(dep[x][0]<dep[y][0])swap(x,y);
	ll now=19;
	while(now>=0)
	{
		if(dep[x][now]>dep[y][0])x=f[x][now];
		now--;
	}
	now=19;
	if(x==y)return x;
	while(now>=0)
	{
		if(f[x][now]!=f[y][now])x=f[x][now],y=f[y][now];
		now--;
	}
	return f[x][0];
}
ll F[400001];
ll ans=0;
void count(ll x,ll fa)
{
	F[x]+=val[x];
	for(ll i=head1[x];i!=0;i=e1[i].next)
	{
		ll u=e1[i].to;
		if(u==fa)continue;
		count(u,x);
		F[x]+=F[u];
	}
}
int main()
{
	n=read();m=read();
	for(ll i=1;i<n;i++)
	{
		ll x=read(),y=read();
		add1(x,y);add1(y,x);
	}
	dfs(1,0,1);
	for(ll i=0;i<=18;i++)
	{
		for(ll j=1;j<=n;j++)
		{
			f[j][i+1]=f[f[j][i]][i];
			dep[j][i+1]=dep[f[j][i]][i];
		}
	}
	for(ll i=1;i<=m;i++)
	{
		ll x=read(),y=read();
		val[x]++;val[y]++;
		val[ask_lca(x,y)]-=2;
	}
	count(1,0);
	for(ll i=2;i<=n;i++)
	{
		if(F[i]>1)continue;
		if(F[i]==1)
			ans++;
		else
			ans+=m;
	}
	cout<<ans<<endl;
	 
	return 0;
}

毀滅吧。