CF516D Drazil and Morning Exercise(up and down,并查集)
文章目录
【注意】最后更新于 February 8, 2020,文中内容可能已过时,请谨慎使用。
题目链接
题意简述
给定一棵 $n$ 个点带边权的树,定义 $d(u)$ 为树上离它最远的点到它的距离,$q$ 次询问,每次询问给定 $l$,求一个最大的树上连通块 $V'$ 的大小,满足 $\forall u, v\in V'$,$|d(u)-d(v)|\le l$。
$1\le n\le 10^5$, $1\le q\le 50$。
简要做法
首先使用 up and down(两遍 dfs,第一遍求往下走的最远距离,第二遍求往上走的最远距离)求出 $d(u)$。
有一个性质:如果以 $d(u)$ 最小的 $u$ 为根,$\forall v, d(v)\ge d(parent(v))$。(下文中的“子树”都是以 $d$ 最小的点为根的。)
简单证明
不难发现,我们只要证明 $u$ 的每个儿子 $v$ 都是子树 $v$ 中 $d$ 最小的,即可归纳地证明原命题。
假设子树 $v$ 中存在一个点 $w$,$d(w)<d(v)$,那么从 $v$ 出发的最长路的第一步一定是 $v$ 到 $w$ 的路径上的第一条边(否则的话,从 $w$ 出发可以走到 $v$ 再走从 $v$ 出发的最长路,就会导致 $d(w)>d(v)$),这样的话,从 $u$ 出发也可以先走到 $v$ 再走 $v$ 出发的最长路,这样的话 $d(u)>d(v)$,与题设矛盾。
题目所求的连通块一定是 $d$ 的大小连续的一段,令所求连通块中 $d$ 最小且离根最近的点为 $u$,由上面的性质不难发现,所求连通块一定在子树 $u$ 中。
如果按 $d$ 从大到小枚举每个点,用并查集维护符合条件的点的连通性以及每块的大小,可以发现,删去一个点(一个 $d>d(u)+l$ 的点)并不影响连通性,只需要将其所在块的大小减一即可。(加入一个点就是合并子树,删去一个点是删去叶子。)
这样的话答案就是过程中最大的一块的大小。
总时间复杂度就是 $O(qn\alpha(n)+n\log n)$ 或 O(qn+nlogn) 或 $O(qn\log n)$。
参考代码
(非常抱歉,使用了 CF 模板 qaq)
#ifndef OUUAN
#pragma GCC optimize("Ofast,no-stack-protector,unroll-loops,fast-math")
#endif
#include<bits/stdc++.h>
#define int LoveLive
//#define FAST_IOSTREAM 1
#define For(i,l,r)for(int i=(l),i##end=(r);i<=i##end;++i)
#define FOR(i,r,l)for(int i=(r),i##end=(l);i>=i##end;--i)
#define SON(i,u)for(int i=head[u];i;i=nxt[i])
#define ms(a,x)memset(a,x,sizeof(a))
#define fi first
#define se second
#define pb emplace_back
#define pq priority_queue
#define isinf(x)(x>=INF?-1:x)
#define y1 why_is_there_a_function_called_y1
#define DEBUG(x)cerr<<(#x)<<":"<<x<<endl
using namespace std;
typedef long long LoveLive;typedef pair<int,int>pii;typedef vector<int>vi;
#ifdef int
const int INF=0x3f3f3f3f3f3f3f3fll;
#else
const int INF=0x3f3f3f3f;
#endif
const double eps=1e-9;mt19937 rng(chrono::steady_clock::now().time_since_epoch().
count());int randint(int l,int r){int out=rng()%(r-l+1)+l;return out>=l?out:out+
r-l+1;}
#ifdef FAST_IOSTREAM
#define br cout<<'\n'
#define sp cout<<' '
long long read(){long long x;cin>>x;return x;}template<typename T>void read(T&x){
cin>>x;}template<typename T>void write(const T&x){cout<<x;}
#else
#define br putchar('\n')
#define sp putchar(' ')
template<typename T>typename enable_if<!is_integral<T>::value,void>::type read(T
&x){cin>>x;}long long read(){char c;long long out=0,f=1;for(c=getchar();!isdigit
(c)&&c!='-';c=getchar());if(c=='-'){f=-1;c=getchar();}for(;isdigit(c);c=getchar())
out=(out<<3)+(out<<1)+c-'0';return out*f;}template<typename T>typename enable_if
<is_integral<T>::value,T>::type read(T&x){char c;T f=1;x=0;for(c=getchar();!isdigit
(c)&&c!='-';c=getchar());if(c=='-'){f=-1;c=getchar();}for(;isdigit(c);c=getchar())
x=(x<<3)+(x<<1)+c-'0';return x*=f;}char read(char&x){for(x=getchar();isspace(x);
x=getchar());return x;}double read(double&x){scanf("%lf",&x);return x;}template<
typename T>typename enable_if<!is_integral<T>::value,void>::type write(const T&x
){cout<<x;}template<typename T>typename enable_if<is_integral<T>::value,void>::type
write(const T&x){if(x<0){putchar('-');write(-x);return;}if(x>9)write(x/10);putchar
(x%10+'0');}void write(const char&x){putchar(x);}void write(const double&x){printf
("%.10lf",x);}
#endif
template<typename T,typename...Args>void read(T&x,Args&...args){read(x);read(args
...);}template<typename OutputIt,typename=typename enable_if<is_same<output_iterator_tag
,typename iterator_traits<OutputIt>::iterator_category>::value||(
is_base_of<forward_iterator_tag,typename iterator_traits<OutputIt>::iterator_category>::value
&&!is_const<OutputIt>::value)>::type>void read(OutputIt __first,OutputIt __last){for(;__first
!=__last;++__first)read(*__first);}template<typename InputIt,typename=typename enable_if
<is_base_of<input_iterator_tag,typename iterator_traits<InputIt>::iterator_category
>::value>::type>void wts(InputIt __first,InputIt __last){bool isFirst=true;for(;
__first!=__last;++__first){if(isFirst)isFirst=false;else sp;write(*__first);}br;}
template<typename InputIt,typename=typename enable_if<is_base_of<input_iterator_tag
,typename iterator_traits<InputIt>::iterator_category>::value>::type>void wtb(InputIt
__first,InputIt __last){for(;__first!=__last;++__first){write(*__first);br;}}template
<typename T>void wts(const T&x){write(x);sp;}template<typename T>void wtb(const
T&x){write(x);br;}template<typename T>void wte(const T&x){write(x);exit(0);}template
<typename T,typename...Args>void wts(const T&x,Args...args){wts(x);wts(args...);}
template<typename T,typename...Args>void wtb(const T&x,Args...args){wts(x);wtb(args
...);}template<typename T,typename...Args>void wte(const T&x,Args...args){wts(x);
wte(args...);}template<typename T>inline bool up(T&x,const T&y){return x<y?x=y,1
:0;}template<typename T>inline bool dn(T&x,const T&y){return y<x?x=y,1:0;}
const int N = 100010;
const int mod = 1000000007;
int head[N], nxt[N << 1], to[N << 1], edge[N << 1], cnt;
int n, f[N], siz[N], id[N], rid[N];
struct Element
{
int fi, se;
Element() { fi = 0; se = -INF; }
void insert(int x)
{
if (x > fi)
{
se = fi;
fi = x;
}
else if (x > se) se = x;
}
int get(int x)
{
if (x == fi) return se;
return fi;
}
} dis[N];
void dfsdn(int u, int fa)
{
SON (i, u)
{
int v = to[i];
int w = edge[i];
if (v == fa) continue;
dfsdn(v, u);
dis[u].insert(dis[v].fi + w);
}
}
void dfsup(int u, int fa)
{
SON (i, u)
{
int v = to[i];
int w = edge[i];
if (v == fa) continue;
dis[v].insert(dis[u].get(dis[v].fi + w) + w);
dfsup(v, u);
}
}
void add(int u, int v, int w)
{
nxt[++cnt] = head[u];
head[u] = cnt;
to[cnt] = v;
edge[cnt] = w;
}
int find(int x)
{
return x == f[x] ? x : f[x] = find(f[x]);
}
void merge(int x, int y)
{
if (find(x) == find(y)) return;
if (siz[find(x)] < siz[find(y)]) swap(x, y);
siz[find(x)] += siz[find(y)];
f[find(y)] = find(x);
}
signed main()
{
#ifdef FAST_IOSTREAM
cin.sync_with_stdio(false);
cin.tie(0);
#endif
read(n);
For (i, 1, n - 1)
{
int u, v, w;
read(u, v, w);
add(u, v, w);
add(v, u, w);
}
dfsdn(1, 0);
dfsup(1, 0);
For (i, 1, n) id[i] = i;
sort(id + 1, id + n + 1, [](int x, int y){return dis[x].fi > dis[y].fi;});
For (i, 1, n) rid[id[i]] = i;
int q = read();
while (q--)
{
int len = read();
int l = 1;
int ans = 0;
For (i, 1, n)
{
f[i] = i;
siz[i] = 1;
}
For (u, 1, n)
{
while (dis[id[l]].fi > dis[id[u]].fi + len) --siz[find(id[l++])];
SON (i, id[u])
{
int v = to[i];
if (rid[v] < u) merge(id[u], v);
}
up(ans, siz[find(id[u])]);
}
wtb(ans);
}
return 0;
}
评论正在加载中...如果评论较长时间无法加载,你可以 搜索对应的 issue 或者 新建一个 issue 。