CodeForces 1321E. World of Darkraft: Battle for Azathoth(线段树)

传送门

题意

给 \(a_1,a_2,...,a_n\),\(b_1,b_2,...,b_m\),\((x_1,y_1,w_1),(x_2,y_2,w_2),...,(x_p,y_p,w_p)\),

\[\max_{1\le i\le n,1\le j\le m}\{\sum_{x_k<a_i,y_k<b_j}w_k-a_i-b_j\}\]
其实就是分别选一个 \(a_i,b_j\),求矩形 \((0,0),(a_i,b_j)\) 内部的点的 \(w\) 总和减 \(a_i+b_j\) 的最大值

题解

这种偏序问题基本上都可以考虑用线段树解决
借助扫描线的思维,枚举 x 轴枚举,线段树维护 y 轴
沿着 x 轴依次将点值加入其 y 轴对应坐标,然后直接查询线段树中的最大值
这个线段树显然应该维护前缀和,这样我们的到的最大值就是前缀和的最大值
就是问题的答案了
当然最初时要将 \(b_j\) 从线段树上减去

代码

#include <iostream>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
typedef long long LL;
typedef pair<int,LL> PII;
const int inf=0x3f3f3f3f;
const LL INF=0x3f3f3f3f3f3f3f3f;
const int MAXN=2e5+10;
const int MAXM=1e6+10;
int n,m,p;
PII a[MAXN],b[MAXN],temp[MAXN];
struct Turp{
    int x,y,w;
}t[MAXN];
bool cmp(Turp a,Turp b){return a.x<b.x;}
struct SegTree{
    #define mid ((l+r)>>1)
    LL maxv[MAXM*4],tag[MAXM*4];
    void pushdown(int id){
        maxv[id<<1]+=tag[id];tag[id<<1]+=tag[id];
        maxv[id<<1|1]+=tag[id];tag[id<<1|1]+=tag[id];
        tag[id]=0;
    }
    void update(int id,int l,int r,int L,int R,LL x,int opt){
        if(L<=l&&r<=R)
            if(opt) {maxv[id]+=x;tag[id]+=x;return;}
            else {maxv[id]=max(maxv[id],x);return;}
        if(tag[id]) pushdown(id);
        if(L<=mid) update(id<<1,l,mid,L,R,x,opt);
        if(R>mid) update(id<<1|1,mid+1,r,L,R,x,opt);
        maxv[id]=max(maxv[id<<1],maxv[id<<1|1]);
    }
    #undef mid
}tr;

int main(){
    scanf("%d%d%d",&n,&m,&p);
    for(int i=1;i<=n;i++) scanf("%d%d",&a[i].first,&a[i].second);
    for(int i=1;i<=m;i++) scanf("%d%d",&b[i].first,&b[i].second);
    for(int i=1;i<=p;i++) scanf("%d%d%d",&t[i].x,&t[i].y,&t[i].w);
    sort(a+1,a+n+1);
    sort(b+1,b+m+1);
    sort(t+1,t+p+1,cmp);
    memset(tr.maxv,0xc0,sizeof(tr.maxv));
    LL temp=-INF;
    for(int i=1e6,j=m;i>=0;i--){
        while(i<b[j].first) temp=max(temp,-b[j].second),j--;
        tr.update(1,0,1e6,i,i,temp,0);
    }
    LL ans=-INF;
    for(int i=1,j=1;i<=n;i++){
        while(j<=p&&t[j].x<a[i].first) tr.update(1,0,1e6,t[j].y,1e6,t[j].w,1),j++;
        ans=max(ans,tr.maxv[1]-a[i].second);
    }
    cout<<ans<<endl;
    return 0;
}

原文地址:https://www.cnblogs.com/BakaCirno/p/12409119.html

时间: 2024-08-30 14:14:17

CodeForces 1321E. World of Darkraft: Battle for Azathoth(线段树)的相关文章

Codeforces 458C Elections 贿赂选票抢主席! 线段树

题目链接:点击打开链接 题意: 给定n张选票,每张选票有2个参数,第一个参数表示这张选票选的人 第二个参数表示如果让这张选票改为选0号 的花费 问:使得0号的选票是最高的(不能有和0号相同)的最小花费 枚举0号的最终选票 那么已知0号最终选票,则有些人选票比0号大的,那些票都要买下来. 如果买完了还是达不到 最终选票,就从所有剩下的选票里找前k小的. 用线段树求前k小的数的和,然后_(:зゝ∠)_就可以了 #include<iostream> #include<cstdio> #i

Codeforces 1136E Nastya Hasn&#39;t Written a Legend (线段树教做人系列)

题意:有一个数组a和一个数组k,数组a一直保持一个性质:a[i + 1] >= a[i] + k[i].有两种操作:1,给某个元素加上x,但是加上之后要保持数组a的性质.比如a[i]加上x之后,a[i + 1]<a[i] + k[i],那么a[i + 1]就变成a[i] + k[i],否则不变.同理,若a[i + 2]小于了现在的a[i + 1] + k[i + 1],那么a[i + 2]也变成a[i + 1] + k[i + 1],一直保持这个性质.第二章操作,询问数组a的区间[l, r]的

CF1321-World of Darkraft: Battle for Azathoth (线段树+二维偏序)

题意: 题目大致意思是给你n把武器,m件防具,p个怪兽,接下来n行每行告诉你该武器的攻击力和花费, 接下来m行告诉你该防具的防御力和花费,然后p行每行告诉你这个怪兽的攻击力,防御力以及打败这个 怪兽可以获得的金钱数,当你的攻击力大于怪兽的防御力,并且你的防御力大于怪兽的攻击力时,你可 以打败这个怪兽.你必须至少购买1件武器和1件防具,问你最多可以获得多少钱. 链接:https://codeforces.com/contest/1321/problem/E 思路: 看了大神的题解,第一次知道二维偏

Codeforces Round #271 (Div. 2) F.Ant colony(线段树 + 统计区间内某数的个数)

F. Ant colony Mole is hungry again. He found one ant colony, consisting of n ants, ordered in a row. Each ant i (1 ≤ i ≤ n) has a strength si. In order to make his dinner more interesting, Mole organizes a version of «Hunger Games» for the ants. He c

Codeforces Round #244 (Div. 2) B. Prison Transfer 线段树rmq

B. Prison Transfer Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/problemset/problem/427/B Description The prison of your city has n prisoners. As the prison can't accommodate all of them, the city mayor has decided to transfer c

Codeforces Round #426 (Div. 2) D. The Bakery(线段树维护dp)

题目链接: Codeforces Round #426 (Div. 2) D. The Bakery 题意: 给你n个数,划分为k段,每段的价值为这一段不同的数的个数,问如何划分,使得价值最大. 题解: 考虑dp[i][j]表示划分为前j个数划分为i段的最大价值,那么这就是一个n*n*k的dp, 考虑转移方程dp[i][j]=max{dp[i][k]+val[k+1][j]},我们用线段树去维护这个max,线段树上每个节点维护的值是dp[i][k]+val[k+1][j],对于每加进来的一个数a

Codeforces Round #424 (Div. 2) E. Cards Sorting(线段树)

题目链接:Codeforces Round #424 (Div. 2) E. Cards Sorting 题意: 将n个数放进一个队列,每次检查队首,看看是不是队列中最小的数,如果是就扔掉,如果不是就放到队尾. 这样直到队列为空,为需要操作多少次. 题解: 考虑用两个指针模拟,最开始now指针指向第一个数,然后nxt指针指向下一个将要被删除的数. 然后我们要算出这里需要移动多少步,然后删掉这个数,一直重复操作,直到将全部的数删完. nxt指针可以用set来维护,now指针可以用并查集来维护. 计

Codeforces Round #603 (Div. 2) E. Editor(线段树)

链接: https://codeforces.com/contest/1263/problem/E 题意: The development of a text editor is a hard problem. You need to implement an extra module for brackets coloring in text. Your editor consists of a line with infinite length and cursor, which point

2014-2015 Codeforces Trainings Season 2 Episode 7 G Gophers --线段树

题意: 有n个地鼠,m个CD碟,每个CD碟有一个影响范围,范围内的地鼠都会被吵到,每次有一个操作就是移动CD碟,然后求每次被影响的地鼠有多少只. 解法: 线段树做.我们只关注地鼠有没有被吵到就可以了,之前我还去把所有可能移到的位置都存下来离散化一下,然后维护也维护错了.一堆bug,真是想多了. 线段树维护两个值:  cntS[rt]表示该段被多少个区间所覆盖, NOG[rt]表示此区间内没有被影响到的地鼠有多少个. 那么我们更新到区间,然后直接pushup即可, 因为更新到区间的时候已经可以确定