Codeforces Round 862 (Div. 2):Place for a Selfie 、A Wide, Wide Graph

Place for a Selfie:

题意:

给你n个过原点的直线和m个抛物线,对每一条抛物线求是否存在一条直线不和其相交。

原题链接:Problem - C - Codeforces

思路:

连立方程组:kx=ax^2+bx+c;

若抛物线与直线不相交则(b-k)^2-4ac<0;

所以我们只需要使b-k的绝对值最小即可,也就是二分查找一下距离b最近的两个k(分别是大于等于b的和小于等于b的),如果这个k无法使(b-k)^2-4ac<0,那么输出NO,否则就输出yes;

考点:二分

代码:

#pragma GCC optimize(2)
#include <iostream>
#include <vector>
#include <queue>
#include <bitset>
#include <map>
#include <cstring>
#include <set>
#include <algorithm>
#define endl "\n"

#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
using namespace std;
const int N=100100;
typedef long long LL;
typedef unsigned long long ULL;
const LL inf=0x3f3f3f3f3f3f3f3f;

LL dt(LL b,LL k,LL a,LL c){
    if((b-k)*(b-k)<4*a*c) return -1;
    else return 1;
}

bool cmp(LL a,LL b){
    return a>b;
}

LL sz[N];
int main(){
    quick_cin();
    LL t;
    cin>>t;
    while(t--){
        LL n,m;
        cin>>n>>m;

        for(int i=0;i<n;i++){
            cin>>sz[i];
        }
        sort(sz,sz+n);
        for(int i=0;i<m;i++){
            LL a,b,c;
            cin>>a>>b>>c;
                int flag=0;
                if(c<=0){
                    cout<<"NO\n";
                }
                else{
                    LL x=lower_bound(sz,sz+n,b)-sz;
                    LL x1=x-1;
                    //cout<<x<<"- "<<x1<<endl;
                    if(dt(b,sz[x],a,c)<0&&x<n&&x>=0){
                        flag=1;
                        cout<<"YES\n";
                        cout<<sz[x]<<endl;
                    }
                    if(dt(b,sz[x1],a,c)<0&&flag==0&&(x<n||sz[x1]<b)&&x1>=0){
                        flag=1;
                        cout<<"YES\n";
                        cout<<sz[x1]<<endl;
                    }
                    if(flag==0) cout<<"NO\n";
                }
        }
    }
    return 0;
}

比赛的时候因为快输卡了好久,真的修的头都炸了。

A Wide, Wide Graph

题意:

给定一颗树,每边的权值为1,要求根据距离重置边,距离大于等于k的两点之间链接一条无向边,问当k={1.....n}时有多少联通块

原题链接:Problem - D - Codeforces

思路:

先给出一个结论:在树中如果某个点距离其他点最长边为k那么他和其他所有最长边>=k的点都在一个联通集里,并且所有最长边<k的点都是孤立的。

那么答案就很显然了,维护一个最长边长度的后缀和ans1 答案就是

if(ans1[k]>0)cout<<(n-ans1[k]+1)<<" ";
        else cout<<n<<" ";

然后维护用dijkstra和树的直径扫一遍就好了

树的直径:

树上的最远的两点之间的路径。

维护树的直径的方法:随机选一个点走一遍dijkstra最长路,那么最远的那个点就是树的直径的一端(flag),再从找到的这一端出发走一遍dijkstra就能找到另一端(flag),然后再从flag走一遍dijkstra就能找到所有点的最长边(ans[])

代码:

#pragma GCC optimize(2)
#include <iostream>
#include <vector>
#include <queue>
#include <bitset>
#include <map>
#include <cstring>
#include <set>
#include <algorithm>
#define endl "\n"

#define quick_cin() cin.tie(0),cout.tie(0),ios::sync_with_stdio(false)
using namespace std;
const int N=300100;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int> PII;
const LL inf=0x3f3f3f3f3f3f3f3f;

int n;
int fa[N];
int idx,h[N],e[N],ne[N];
int dist[N];
int ans[N];
int ans1[N];
bool st[N];

void add(int a,int b){
    e[idx]=b;
    ne[idx]=h[a];
    h[a]=idx++;
}

void dijkstra(int x){
    memset(st,0,sizeof st);
    memset(dist,0,sizeof dist);
    priority_queue<PII,vector<PII>,less<PII> > q;
    q.push({0,x});
    dist[x]=0;
    while(q.size()){
        int t=q.top().second;
        q.pop();
        if(st[t])continue;
        st[t]=1;
        for(int i=h[t];i!=-1;i=ne[i]){
            int j=e[i];
            if(dist[j]<dist[t]+1&&st[j]==0){
                dist[j]=dist[t]+1;
                q.push({dist[j],j});
            }
        }
    }
}


int main(){
    //quick_cin();
    memset(h,-1,sizeof h);
    cin>>n;
    for(int i=0;i<n-1;i++){
        int a,b;
        cin>>a>>b;
        add(a,b);
        add(b,a);
    }
    dijkstra(1);
    int maxl=0,flag=0;
    for(int i=1;i<=n;i++){
        if(maxl<dist[i]){
            maxl=dist[i];
            flag=i;
        }
        ans[i]=dist[i];
    }
    dijkstra(flag);
    maxl=0;
    for(int i=1;i<=n;i++){
        if(maxl<dist[i]){
            maxl=dist[i];
            flag=i;
        }
        ans[i]=max(dist[i],ans[i]);
    }
    dijkstra(flag);
    for(int i=1;i<=n;i++){
        if(maxl<dist[i]){
            maxl=dist[i];
            flag=i;
        }
        ans[i]=max(dist[i],ans[i]);
        ans1[ans[i]]++;
    }
    for(int i=n-1;i>0;i--){
        ans1[i]+=ans1[i+1];
    }
    for(int i=1;i<=n;i++){
        if(ans1[i]>0)cout<<(n-ans1[i]+1)<<" ";
        else cout<<n<<" ";
    }
    return 0;
}

为了修那个c题没来及做,我真的,受不了啦!!!!!!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值