Codeforces Round #329 (Div. 2) B, D

B. Anton and Lines

思路:

画个图就明白了,在区间 [x1,x2] 之间如果两条线段有交点,那么必定有下面的关系,所以我们可以求出所有直线上横坐标为 x1 x2 的点的纵坐标记为 L,R ,然后排一下序最后查找是否存在 L 教大但是R 较小就OK了!怎么做呢?直接扫一遍加判断就好了。而且直接判断 p[i].SD<p[i1].SD 就行了,想想为什么!
另:注意爆long long的问题!

线段相交

代码:
#include <cstdio>
#include <cstring>
#include <queue>
#include <algorithm>
#include <iostream>
#include <cmath>
#include <map>
#include <vector>
#include <set>
#include <string>
#define PB push_back
#define FT first
#define SD second
#define MP make_pair
#define INF 0x3f3f3f3f
using namespace std;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<LL,LL>  P;
const int maxn=10+1e5,MOD=7+1e9;
P p[maxn];
bool cmp(P a,P b)
{
    if(a.FT == b.FT) return a.SD < b.SD;
    return a.FT < b.FT;
}
int main()
{
    int n;
    int x1,x2;
    scanf("%d%d%d",&n, &x1, &x2);
    for(int i=0;i<n;i++){
        int k,b;
        scanf("%d%d",&k,&b);
        p[i].FT = 1LL*x1*k + b;
        p[i].SD = 1LL*x2*k + b;
    }
    sort(p,p+n,cmp);
    bool ok=0;
    for(int i=1;i<n;i++){
        if(p[i].SD < p[i-1].SD) {
            ok=1;
            break;
        }
    }
    if(ok) puts("YES");
    else puts("NO");
    return 0;
}

D. Happy Tree Party

思路:

对于从 a -> b 的路径,如果边权值为1,则值不变,否则就是 1 边权值,这样的话最多除64次就为0也就不需要继续除下去了,所以问题的关键在于去压缩哪些连续的边权为1的路径,这里自然就想到并查集啦,具体实现看代码吧!
另:因为更改后的边权值只会变小,所以只会涉及到集合并和查的操作。这一点要想懂。

#include <cstdio>
#include <cstring>
#include <iostream>
#include <vector>
#define PB push_back
#define MP make_pair
#define FT first
#define SD second
using namespace std;
const int N = 10+2e5;
typedef pair<int,int> PII;
typedef long long LL;
int n, m;
int dep[N], st[N];
LL w[N];
vector<PII> G[N];
PII pre[N];
void dfs(int u,int fa)
{
    dep[u] = dep[fa]+1;
    for(int i = 0;i < G[u].size();i ++) {
        int v = G[u][i].FT;
        int id = G[u][i].SD;
        if(v == fa) continue;
        pre[v] = MP(u,id);
        dfs(v,u);
    }
}
int find_set(int u)
{ 
    if(w[pre[u].SD] != 1) return u;
    if(st[u] == u)
        return st[u] = find_set(pre[u].FT);
    return st[u] = find_set(st[u]); 
}
int jmp(int a,LL &v)
{
    int id = pre[a].SD;
    if(w[id] > 1) {
        v /= w[id];
        return pre[a].FT;
    }
    return st[a] = find_set(st[a]);
}
LL cal(int a,int b,LL v)
{
    while(v && a!=b) {
        if(dep[a] < dep[b]) swap(a,b);
        a = jmp(a,v);
    }
    return v;
}
int main()
{
    // freopen("in.txt","r",stdin);
    scanf("%d%d",&n, &m);
    for(int i = 1;i < n;i ++) {
        int u,v;
        scanf("%d%d%I64d",&u,&v,&w[i]);
        G[u].PB(MP(v,i)), G[v].PB(MP(u,i));
    }
    dfs(1,0);
    for(int i = 1;i <= n;i ++) st[i] = i;
    while(m --){
        int tp;
        scanf("%d",&tp);
        if(tp == 1) {
            int a, b;
            LL y;
            scanf("%d%d%I64d",&a, &b, &y);
            printf("%I64d\n",cal(a,b,y));
        }
        else {
            int p;
            LL c;
            scanf("%d%I64d",&p, &c);
            w[p] = c;
        }
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值