件名の説明:
ファーマージョンは、便利な番号の彼の納屋にNNNの屋台の間で牛乳を輸送するN-1N-1N-1のパイプの新しいシステム(2≤N≤50,0002\当量のNの\の当量50,0002≤N≤50,000)がインストールされています1 ... N1 \ ldots N1 ... N。各パイプは、ストールの対を接続し、すべてのストールは、パイプの経路を介して、相互に接続されています。
FJは(1≤K≤100,0001\当量K \当量100,0001≤K≤100,000)屋台のKKKのペアの間で牛乳をポンピングされます。iiithなペアでは、2台の屋台sis_isiとtit_iti、ミルクは単位レートで励起されて、それに沿ってパスのエンドポイントを語っています。FJは、ストールがミルクが励起され、それに沿ってKKKパスの多くに沿ってウェイポイントとして機能することができますので、いくつかの屋台が、それらを介してポンピングされるすべての牛乳に圧倒終わるかもしれないことを懸念しています。彼はどんなストールを介してポンピングされている牛乳の最大量を決定するのに役立ちます。ミルクがtit_itiするsis_isiからのパスに沿って圧送されている場合は、それがエンドポイント屋台sis_isiを通って圧送されたものとしてカウントし、
tit_itiだけでなく、それらの間のパスに沿ってすべての失速による。
導管(2≤N≤50,000)区画のN-1の間の彼の納屋NインストールにFJは、コンパートメントは1からNまで番号が付けられています すべてのコンパートメントは、通信パイプです。
そこFJ K(1≤K≤100,000)ミルク輸送経路、コンパートメントのSi Tiに対するi番目の区画から通じる経路。圧力輸送ルートのコンパートメントを与えると、2つのエンドポイントの真ん中ルートのすべてのコンパートメントは、ユニットの輸送に圧力をもたらすためには、あなたはコンパートメントがある最大圧力を計算する必要があります。
入力形式
入力の最初の行はNNNとKKKが含まれています。
次のN-1N-1N-1行はそれぞれパイプを記述する二つの整数のXXXとYYY(X≠Y-X \ NE YX≠y)を含みます
XXXとYYY屋台の間。
次KKK線は、各エンドポイントを記述する二つの整数のSSSとTTTを含みます
ミルクが圧送されてされる経路の屋台。
出力フォーマット
牛乳の最大量を指定する整数で任意失速を通してポンピング
納屋。
サンプル入力と出力
入力#1
5 10
3 4
1 5
4 2
5 4
5 4
5 4
3 5
4 3
4 3
1 3
3 5
5 4
1 5
3 4
出力#1
9
アイデア:
ここでは、マップに描かれたサンプルは、より多くのタイトルの意味を理解することができます。これは、それを通して点の最大数を求め、一点からエッジ、k番目のクエリの原点に沿って別の時間を与えるために頼まkのビューに権利があります。
このように言えば、ツリーポイント差を考え、それは点tに点sから想定される、によって差分アレイ\(DIF [S] ++、 DIF [T] ++、DIF [LCA(S、T )] - 、DIF [F [LCA(S、T)] [0]] - \) 、統計のそれぞれに渡された点の数が、最大値はバックトラックの間に得ることができます。
スターへのチェーンとフロントの実現には、LCA手法は、ブログ上で見つけることができます求めていました。
コード:
#include <iostream>
#include <cstdio>
using namespace std;
#define max_n 50005
//前向星
int head[max_n];
struct edge
{
int v;
int next;
}e[max_n<<1];
int cnt = 0;
void add(int u,int v)
{
++cnt;
e[cnt].v = v;
e[cnt].next = head[u];
head[u] = cnt;
}
//读入优化
inline void read(int& x)
{
x = 0;int f=0;char ch = getchar();
while(ch<'0'||ch>'9') {if(ch=='-')f=1;ch=getchar();}
while('0'<=ch&&ch<='9') {x = 10*x+ch-'0';ch=getchar();}
x = f?-x:x;
}
//题目数据
int n,k;
int ans = 0;
int f[max_n][23];
int depth[max_n];
int dif[max_n];//差分数组
//求lca
void dfs(int u,int from)
{
depth[u] = depth[from]+1;
for(int i = 1;(1<<i)<=depth[u];i++)
{
f[u][i] = f[f[u][i-1]][i-1];
}
for(int i = head[u];i;i=e[i].next)
{
int v = e[i].v;
if(from==v) continue;
f[v][0] = u;
dfs(v,u);
}
}
int lca(int s,int t)
{
if(depth[s]<depth[t]) swap(s,t);
for(int i = 20;i>=0;i--)
{
if(depth[f[s][i]]>=depth[t])
{
s =f[s][i];
}
if(s==t)
{
return s;
}
}
for(int i = 20;i>=0;i--)
{
if(f[s][i]!=f[t][i])
{
s = f[s][i];
t = f[t][i];
}
}
return f[s][0];
}
//统计节点最大经过次数
void maxsum(int u,int from)
{
for(int i = head[u];i;i=e[i].next)
{
int v = e[i].v;
if(v==from) continue;
maxsum(v,u);
dif[u] += dif[v];
}
ans = max(ans,dif[u]);
}
int main()
{
read(n);read(k);
//cout << "n " << n << " k " << k << endl;
for(int i = 1;i<n;i++)
{
int u,v;
read(u);
read(v);
add(u,v);
add(v,u);
}
dfs(1,0);
for(int i = 0;i<k;i++)
{
int u,v;
read(u);
read(v);
int LCA = lca(u,v);
dif[u]++;
dif[v]++;
dif[LCA]--;
dif[f[LCA][0]]--;
}
maxsum(1,0);
cout << ans << endl;
return 0;
}
参考記事:
顾z,差分数组 and 树上差分,https://rpdreamer.blog.luogu.org/ci-fen-and-shu-shang-ci-fen (洛谷出品!必属精品!,讲的虽然基础,但hin清晰)
思结,树上差分的两种思路,https://www.luogu.org/blog/sincereactor/shu-shang-ci-fen-di-liang-zhong-sai-lu (同为洛谷博客,可对照参考)