gym102452C牧場の建設2019 ICPC香港ライブコンテスト

https://codeforces.com/gym/102452/problem/C

このようなパスがいくつ条件を満たすかは、一目でポイントの分割と征服の問題ですが、半年以上は書いていません。幸いなことに、チームメイトに伝えた後、チームメイトは1時間1Aになります。この質問をまとめて、分割と征服のポイントを確認しましょう。チームメイトに常に頼ることはできません。

まず、単純なポリゴンを形成する条件はsum> 2 * mxです。これは、三角形の2つの辺の合計が3番目の辺よりも大きいことで類推できます。

この質問の辺の長さは1e9レベルなので、維持するためにツリー配列を使用する必要があります。trueとマークされていないサブツリーを取り出し、ルートノードから各ポイントまでのパスの長さの合計とパス上の最大値mxを見つけ、すべてのパスの長さの合計を離散化してから、mxを並べ替えます。それらをツリー配列に追加してから、ツリー配列に保存されているパスの最大値<現在の列挙パスの<mxを追加します。これにより、離散化された重み配列の上限を満たす位置を直接見つけることができ、それを使用できます。接頭辞の合計により、現在のパスと組み合わせて条件を満たすパスを形成できる数がわかります。

それは離散化されることになるため、許容範囲と除外の表現を使用するのが最善です。すべてのパスの長さを見つけて、許容範囲を取り出すことができます。

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef pair<ll,ll> p;
const int maxl=2e5+10;

int n,len,tot;ll ans;
ll a[maxl],num[maxl],b[maxl],dis[maxl];
vector<int> e[maxl];
vector<p> pth;
bool vis[maxl];

struct ctr
{
	int ans,n,mi;
	int son[maxl];
	inline void dfs(int u,int fa)
	{
		son[u]=1;int ret=0;
		for(int v:e[u])
		if(!vis[v] && v!=fa)
		{
			dfs(v,u);
			son[u]+=son[v];
			ret=max(son[v],ret);
		}
		ret=max(ret,n-son[u]);
		if(ret<mi)
		{
			ans=u;
			mi=ret;
		}
	}
	inline int getct(int u)
	{
		ans=0;mi=2e9;
		dfs(u,0);
		return ans;
	}
}ct;

inline void prework()
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]),e[i].clear(),vis[i]=false;
	int u,v;
	for(int i=1;i<=n-1;i++)
	{
		scanf("%d%d",&u,&v);
		e[u].push_back(v);
		e[v].push_back(u);
	}
}

inline ll getsum(int i)
{
	ll ret=0;
	while(i)
	{
		ret+=b[i];
		i-=i&-i;
	}
	return ret;
}
inline void add(int i,ll val,int n)
{
	while(i<=n)
	{
		b[i]+=val;
		i+=i&-i;
	}
}

inline void getval(int u,ll mx,ll sum,int fa)
{
	mx=max(mx,a[u]);sum+=a[u];
	pth.push_back({mx,sum});
	for(int v:e[u])
	if(!vis[v] && v!=fa)
		getval(v,mx,sum,u);
}

inline ll calc(int u,ll w,int fa)
{
	tot=0;pth.clear();
	getval(u,w,w,fa);
	for(p d:pth)
		num[++tot]=d.second;
	sort(num+1,num+1+tot);
	tot=unique(num+1,num+1+tot)-num-1;
	sort(pth.begin(),pth.end());
	ll mx,sum,val=(w>0)?w:a[u],ret=0;int pos;
	for(p d:pth)
	{
		mx=d.first;sum=d.second;
		pos=upper_bound(num+1,num+1+tot,2*mx-sum+val)-num;
		if(pos<=tot)
			ret+=getsum(tot)-getsum(pos-1);
		pos=lower_bound(num+1,num+1+tot,sum)-num;
		add(pos,1ll,tot);
	}
	for(p d:pth)
	{
		sum=d.second;
		pos=lower_bound(num+1,num+1+tot,sum)-num;
		add(pos,-1ll,tot);
	}
	return ret;
}

inline void solv(int u)
{
	vis[u]=true;ans+=calc(u,0ll,0);
	int rt;
	for(int v:e[u])
	if(!vis[v])
	{
		ans-=calc(v,a[u],u);
		ct.n=ct.son[v];
		rt=ct.getct(v);
		solv(rt);
	}
}

inline void mainwork()
{
	ct.n=n;
	int rt=ct.getct(1);
	ans=0;
	solv(rt);
}

inline void print()
{
	printf("%lld\n",ans);
}

int main()
{
	int t;
	scanf("%d",&t);
	for(int i=1;i<=t;i++)
	{
		prework();
		mainwork();
		print();
	}
	return 0;
}

 

おすすめ

転載: blog.csdn.net/liufengwei1/article/details/108478079