Codeforces Round 862 (Div. 2)(C~E)

Problem - C - Codeforces

思路:

  1. 抛物线与直线有无交点问题可以转化为方程有无解问题,判断方程是否有解,可以使用判别式\Delta =(b-k)^{2}-4*a*c<0,二分寻找所有所有k中离b最近的一个即可
#include <bits/stdc++.h>
using namespace std;
#define ll     long long
#define endl             "\n"
#define int ll
typedef unsigned long long ull;
typedef pair<long long, long long> pll;
typedef pair<int, int> pii;

//double 型memset最大127,最小128
//std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 1e5 + 10;

int d[N];
int n,m;

int toit(int x)
{
	int l=1,r=n,ans=INF,book=0;
	while (l<=r)
		{
			int mid=l+((r-l)>>1);
			if (abs(d[mid]-x)<ans)ans=abs(d[mid]-x),book=mid;
			if (d[mid]>=x)	r=mid-1;
			else l=mid+1;
		}
	return d[book];
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	int t;
	cin>>t;
	while (t--)
		{

			cin>>n>>m;
			for (int i=1; i<=n; ++i)cin>>d[i];
			sort(d+1,d+1+n);
			d[0]=INF;
			int a,b,c;
			while (m--)
				{
					cin>>a>>b>>c;
					int k=toit(b);
					int tmp=(k-b)*(k-b)-4*a*c;
					if (tmp<0)
						{
							cout<<"YES"<<endl;
							cout<<k<<endl;
						}
					else cout<<"NO"<<endl;
				}
		}
	system("pause");
	return 0;
}

Problem - D - Codeforces

思路:

  1.  显然,我们只需要知道每个点位处的路径最长可以多长就可以知道答案

  2. 学习过树的直径,我们知道2遍dfs可以确定树的最长直径。

  3. 如果我们把第二遍dfs搜出来的深度最深的点再来一遍dfs,可以求出每个点所属最长路径

#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
#define endll            endl<<endl
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
//---------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------//
//double 型memset最大127,最小128
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 1e5 + 10;

vector<int>edge[N];

void dfs(int u,int fa,vector<int>&dep)
{
	dep[u]=dep[fa]+1;
	for (auto v:edge[u])if (v!=fa)dfs(v,u,dep);
}

void mysolve()
{
	int n;
	int u,v;
	cin>>n;
	for (int i=1; i<n; ++i)cin>>u>>v,edge[u].push_back(v),edge[v].push_back(u);
	vector<int>dep1(n+1),dep2(n+1);
	dep1[0]=dep2[0]=-1;
	dfs(1,0,dep1);
	int a=max_element(dep1.begin()+1,dep1.end())-dep1.begin();
	dfs(a,0,dep1);
	int b=max_element(dep1.begin()+1,dep1.end())-dep1.begin();
	dfs(b,0,dep2);//三遍dfs
	vector<int>d(n+1);
	for (int i=1; i<=n; ++i)d[i]=max(dep1[i],dep2[i]);//每个点后两次的最深深度就是他们能处于的最长树径
	sort(d.begin()+1,d.end());
	int ans=1,p=1;
	for (int i=1; i<=n; ++i)
		{
			while (ans<n&&p<=n&&d[p]<i)ans++,p++;
			cout<<ans<<" \n"[i==n];
		}
}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	//cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

 Problem - E - Codeforces

思路:

  1. 首先,如果没有一个点出现2次及以上,答案都是0
  2. 因为我们每次都是割一条边,如果最大值点M出现3次及以上,是不是怎样都会有至少2个点在同一棵树上,答案全部是M 
  3. 所以,我们只需要考虑M只出现两次的情况,那么在这两个出现的点x,y的最短路径上的边答案需要我们求,其余答案都是M
    1. 首先,我们可以用dfs求出xy路径上的点和边。
    2. 然后,我们可以从x点(的子树)开始,不断往y处一个个点(一开始是整棵树)侵蚀过去,把本来的树吞噬掉。每次到达路径上一个点,就可以求解路径上每条边的val
    3. 为了不重复侵蚀,我们每次dfs侵蚀,可以标记他的左边界与右边界,保证不重复去蓝色部分,也不去相邻的在路径上的点,只侵蚀当前路径点及其子树(非路径点部分)

#include <bits/stdc++.h>
using namespace std;
#define ll               long long
#define endl             "\n"
#define int              long long
#define endll            endl<<endl
typedef unsigned long long ull;
typedef pair<int, int> pii;
typedef pair<long long, long long> pll;
//---------------------------------------------------------------------------------------------------------------------//
//---------------------------------------------------------------------------------------------------------------------//
//double 型memset最大127,最小128
const int INF = 0x3f3f3f3f;         //int型的INF
const ll llINF = 0x3f3f3f3f3f3f3f3f;//ll型的llINF
const int N = 2e5 + 10;
set<int>st1,st2;
unordered_map<int,int>cnt1,cnt2;
vector<pii>edge[N];
pii b[N];
int a[N];
int ans1,ans2;
bool vis[N];
vector<int>path,inpath;

bool dfs1(int u,int tar)//dfs求路径点与边
{
	path.push_back(u);
	vis[u]=1;
	if (u==tar)return 1;
	for (auto [v,in]:edge[u])
		{
			if (vis[v])continue;
			inpath.push_back(in);
			if (dfs1(v,tar))return 1;
			inpath.pop_back();
		}
	path.pop_back();
	return 0;
}

void todis(int u,int l,int r)//更新蓝色侵蚀部分
{
	cnt1[a[u]]--,cnt2[a[u]]++;
	if (cnt1[a[u]]<2)st1.erase(a[u]);
	if (cnt2[a[u]]>1)st2.insert(a[u]);
	for (auto [v,in]:edge[u])
		{
			if (v!=l&&v!=r)
				{
					todis(v,u,0);
				}
		}
}

int dis()//获取当前两个子树的最大M
{
	int ans=0;
	if (!st1.empty())ans=max(ans,*st1.rbegin());
	if (!st2.empty())ans=max(ans,*st2.rbegin());
	return ans;
}

void mysolve()
{
	int n;
	cin>>n;
	int x,y;
	for (int i=1; i<n; ++i)
		{
			cin>>x>>y;
			edge[x].push_back({y,i}),edge[y].push_back({x,i});//存储信息是对应的点及边的编号
		}
	for (int i=1; i<=n; ++i)
		{
			cin>>a[i];
			cnt1[a[i]]++;
			if (cnt1[a[i]]>1)st1.insert(a[i]);
		}
	if (st1.empty())for (int i=1; i<n; ++i)cout<<0<<endl;
	else if (cnt1[*st1.rbegin()]>2)for (int i=1; i<n; ++i)cout<<(*st1.rbegin())<<endl;
	else
		{
			vector<int>ans(n+1);
			for (int i=1; i<n; ++i)ans[i]=(*st1.rbegin());
			set<int>point;//记录x,y点
			for (int i=1; i<=n; ++i)if (a[i]==*st1.rbegin())point.insert(i);
			dfs1(*point.begin(),*point.rbegin());//找xy路径
			todis(path[0],path[1],0);
			ans[inpath[0]]=dis();
			for (int i=1; i+1<(int)path.size(); ++i)
				{
					todis(path[i],path[i-1],path[i+1]);
					ans[inpath[i]]=dis();
				}
			for (int i=1; i<n; ++i)cout<<ans[i]<<endl;
		}

}

int32_t main()
{
	std::ios::sync_with_stdio(0), cin.tie(0), cout.tie(0);
	ll t=1;
	//cin >> t;
	while (t--)
		{
			mysolve();
		}
	system("pause");
	return 0;
}

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值