Problem - C - Codeforces
思路:
- 抛物线与直线有无交点问题可以转化为方程有无解问题,判断方程是否有解,可以使用判别式
,二分寻找所有所有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
思路:
-
显然,我们只需要知道每个点位处的路径最长可以多长就可以知道答案
-
学习过树的直径,我们知道2遍dfs可以确定树的最长直径。
-
如果我们把第二遍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
思路:
- 首先,如果没有一个点出现2次及以上,答案都是0
- 因为我们每次都是割一条边,如果最大值点M出现3次及以上,是不是怎样都会有至少2个点在同一棵树上,答案全部是M
- 所以,我们只需要考虑M只出现两次的情况,那么在这两个出现的点x,y的最短路径上的边答案需要我们求,其余答案都是M
- 首先,我们可以用dfs求出xy路径上的点和边。
- 然后,我们可以从x点(的子树)开始,不断往y处一个个点(一开始是整棵树)侵蚀过去,把本来的树吞噬掉。每次到达路径上一个点,就可以求解路径上每条边的val
- 为了不重复侵蚀,我们每次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;
}