51nod打广告 1480

题意:

1480 打广告
1.0 秒 131,072.0 KB 80 分 5级题

在这里插入图片描述

输入
单组测试数据。
第一行有两个整数n 和 m (1 ≤ n, m ≤ 2*10^5),表示广告数目和电视频道的数目。
接下来n行,每行两个整数 li, ri (0≤ li ≤ ri ≤ 10^9) ,表示每个广告的区间。
接下来m行,每行三个整数 aj, bj, cj (0 ≤ aj ≤ bj ≤ 10^9, 1 ≤ cj ≤ 10^9)。
输出
输出一个最大值,如果不能找到一个有效的方案,输出0。
输入样例
2 3
7 9
1 4
2 8 2
0 4 1
8 9 3
输出样例
4

思路:

(1)首先,明确题意,要从n个广告里面选择1个,在m个电视台上选择一个播放这个广告,问影响系数最大是多少??

(2)二分 + 线段树

代码实现:

//线段树求区间交
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<cmath>
using namespace std;
typedef long long ll;
const int maxn = 2e5 + 5;

struct Node{
    int l;
    int r;
}node[maxn];
Node G[maxn];
int cnt = 0;

ll seg[maxn << 2];

bool cmp(Node a,Node b){//排序,去除包含关系
    if(a.l != b.l) return a.l < b.l;
    else return a.r > b.r;
}

void push_up(int k){
    seg[k] = max(seg[k << 1],seg[k << 1|1]);
    //为什么要取较大的值??
    //线段树的每个节点代表的也是一个区间
    //取得的最大值代表一段连续的区间中长度最长的区间长度是多少
}

ll operator&(Node a,Node b){
    if(a.l <= b.l&&a.r >= b.r) return b.r - b.l;
    if(a.l >= b.l&&a.r <= b.r) return a.r - a.l;
    return max(min(a.r,b.r)-max(a.l,b.l),0);
}

void build(int k,int l,int r){//建立线段树
    if(l == r){
        seg[k] = G[l].l - G[l].r;
        return ;
    }
    int mid = (l + r) >> 1;
    build(k << 1,l,mid);
    build(k << 1|1,mid + 1,r);
    push_up(k);
}

ll query(int k,int l,int r,int L,int R){
    //查询?? 查询包含在L到R区间中最长的区间长度
    if(L <= l&&R >= r){
        return seg[k];
    }
    int mid = (l + r) >> 1;
    if(R <= mid) return query(k<<1,l,mid,L,R);
    else if(L > mid) return query(k<<1|1,mid+1,r,L,R);
    else return max(query(k<<1,l,mid,L,R),query(k<<1|1,mid+1,r,L,R));
}

int main(){
    int n,m;
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n;i++){//输入左右区间
        scanf("%d%d",&node[i].l,&node[i].r);
    }
    sort(node + 1,node + 1 + n,cmp);
    int now = 1;
    G[++cnt] = node[now];
    for(int i = 1;i <= n;i++){//去掉包含关系
        if(node[i].r > node[now].r){
            G[++cnt] = node[i];
            now = i;
        }
    }
    build(1,1,cnt);//建立线段树
    int a,b,c;
    ll ans = 0;
    for(int i = 1;i <= m;i++){
        scanf("%d%d%d",&a,&b,&c);
        int l = 1,r = cnt + 1,mid,L,R;
        while(l < r){
            mid = (l + r) >> 1;
            if(l == mid) break;
            if(G[mid].l < a){
            	l = mid;
			}
            else r = mid;
        }
        ans = max(ans,((Node){a,b}&G[l])*c);//区间交集的长度*c
        L = l + 1; l = 1; r = cnt + 1;
        while(l < r){
            mid = (l + r) >> 1;
            if(l == mid) break;
            if(G[mid].r > b){
            	r = mid;
			}
            else l = mid;
        }
        ans = max(ans,((Node){a,b}&G[r])*c);//答案怎么求??
        R = r - 1;
        if(R >= L){
            ans = max(ans,query(1,1,cnt,L,R)*c);
        }
    }
    printf("%lld\n",ans);
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值