【tyvj】P2065 「Poetize10」封印一击(贪心+线段树/差分)

http://new.tyvj.cn/p/2065

我就不说我很sb的用线段树来维护值。。。。。。

本机自测的时候想了老半天没想出怎么维护点在所有区间被多少区间包含的方法。最后一小时才想出来线段树(果然太弱)

。。

首先想到贪心,答案一定是某个区间的右端点。。。(这个很容易想也容易证,我就不说了。。。。。)

然后按右端点排序

然后我维护了个左端点前缀和,将来枚举每一个右端点的时候所得到的答案就是sum[n]-sum[i]-he+ge*a[i].r

he表示包含右端点的所有区间的左端点之和,ge表示包含这个点的区间个数。(均不包括自己)

。。

然后离散一下端点用线段树就可以维护he和ge了。。。。

。。

噗,为嘛我没想到直接差分就行了。。。。。。。。

我们直接枚举每个端点,然后维护一个左端点的(后缀和,应该这么说对吧。。。。),每遇到一个左端点就剪掉,就是he,ge数就++同理。。。。。

遇到右端点ge就--且更新答案。QAQ

然后就行了。。

#include <iostream>
#include <cstdlib>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <string>
using namespace std;
typedef long long ll;
const int max(const int &a, const int &b) { return a>b?a:b; }
const int min(const int &a, const int &b) { return a<b?a:b; }
#define read(x) scanf("%d", &x)
#define error(x) if(x) { puts("error"); }
#define dbg(x) cout << (#x) << " = " << x << endl
#define rep(i, n) for(int i=0; i<n; ++i)
#define for1(i,a,n) for(int i=(a); i<=(n); ++i)
#define for2(i,a,n) for(int i=(a); i<(n); ++i)
#define for3(i,a,n) for(int i=(a); i>=(n); ++i)
#define for4(i,a,n) for(int i=(a); i>(n); ++i)

#define lc x<<1
#define rc x<<1|1
#define lson l, m, lc
#define rson m+1, r, rc
#define MID (l+r)>>1

const int N=1e5+10;
struct dat { ll l, r; int pl, pr; }a[N];
struct Tre { int s; ll sum; }t[N<<4];
void pushup(int x) { t[x].s=t[lc].s+t[rc].s; t[x].sum=t[lc].sum+t[rc].sum; }
void update(int l, int r, int x, int pos, ll sum, int k) {
	if(l==r) {
		t[x].s+=k;
		t[x].sum+=sum;
		return;
	}
	int m=MID;
	if(pos<=m) update(lson, pos, sum, k); else update(rson, pos, sum, k);
	pushup(x);
}
int ask1(int l, int r, int x, int L, int R) {
	if(L<=l && r<=R) return t[x].s;
	int m=MID, ret=0;
	if(L<=m) ret+=ask1(lson, L, R); if(m<R) ret+=ask1(rson, L, R);
	return ret;
}
ll ask2(int l, int r, int x, int L, int R) {
	if(L<=l && r<=R) return t[x].sum;
	int m=MID; ll ret=0;
	if(L<=m) ret+=ask2(lson, L, R); if(m<R) ret+=ask2(rson, L, R);
	return ret;
}
bool cmp(const dat &a, const dat &b) { return a.r<b.r; }
int n, num;
ll sum[N], he, ans, E, ge, b[N<<1];
int main() {
	read(n);
	for1(i, 1, n) read(a[i].l), read(a[i].r), b[++num]=a[i].l, b[++num]=a[i].r;

	sort(a+1, a+1+n, cmp);
	sort(b+1, b+1+num);
	num=unique(b+1, b+1+num)-b-1;
	for1(i, 1, n) a[i].pl=lower_bound(b+1, b+1+num, a[i].l)-b;
	for1(i, 1, n) a[i].pr=lower_bound(b+1, b+1+num, a[i].r)-b;
	for1(i, 1, n) update(1, num, 1, a[i].pl, a[i].l, 1);

	for1(i, 1, n) sum[i]=sum[i-1]+a[i].l;
	for1(i, 1, n) {
		update(1, num, 1, a[i].pl, -a[i].l, -1);
		while(a[i].r==a[i+1].r) {
			++i;
			update(1, num, 1, a[i].pl, -a[i].l, -1);
		}
		ge=ask1(1, num, 1, 1, a[i].pr);
		he=ask2(1, num, 1, 1, a[i].pr);
		ll tp=sum[n]-sum[i]-he+ge*a[i].r+a[i].r;
		if(tp>ans) {
			ans=tp;
			E=a[i].r;
		}
	}
	printf("%lld %lld\n", E, ans);
	return 0;
}

  


背景

“圣主applepi于公元2011年9月创造了Nescafe,它在散发了16次光辉之后与公元2011年11月12日被封印为一颗魂珠,贮藏于Nescafe神塔之中。公元2012年9月,圣主带领四大护法重启了Nescafe,如今已经是Nescafe之魂的第30次传播了。不久,它就要被第二次封印,而变成一座神杯……”applepi思索着Nescafe的历史,准备着第二次封印。

描述

Nescafe由n种元素组成(编号为1~n),第i种元素有一个封印区间[ai,bi]。当封印力度E小于ai时,该元素将获得ai的封印能量;当封印力度E在ai到bi之间时,该元素将获得E的封印能量;而当封印力度E大于bi时,该元素将被破坏从而不能获得任何封印能量。现在圣主applepi想选择恰当的E,使得封印获得的总能量尽可能高。为了封印的最后一击尽量完美,就请你写个程序帮他计算一下吧!

输入格式

第一行一个整数N。
接下来N行每行两个整数ai、bi,第i+1行表示第i种元素的封印区间。

输出格式

两个用空格隔开的整数,第一个数是能够获得最多总能量的封印力度E,第二个数是获得的总能量大小。当存在多个E能够获得最多总能量时,输出最小的E。

测试样例1

输入

2
5 10
20 25

输出

10 30

备注

对于 50% 的数据,1<=N<=1000,1<=ai<=bi<=10000。 
对于 100% 的数据,1<=N<=10^5,1<=ai<=bi<=10^9。

时间: 2024-10-14 10:59:04

【tyvj】P2065 「Poetize10」封印一击(贪心+线段树/差分)的相关文章

「Poetize10」封印一击

描述 Description Nescafe由n种元素组成(编号为1~n), 第i种元素有一个封印区间[ai,bi].当封印力度E小于ai时,该元素将获得ai的封印能量:当封印力度E在ai到bi之间时,该元素将获得E的封印 能量:而当封印力度E大于bi时,该元素将被破坏从而不能获得任何封印能量.现在圣主applepi想选择恰当的E,使得封印获得的总能量尽可能高.为了 封印的最后一击尽量完美,就请你写个程序帮他计算一下吧! 题解:首先必须离散化,然后差分可以算出在区间外且<a[i]的总得分,再差分

loj2537 「PKUWC2018」Minimax 【概率 + 线段树合并】

题目链接 loj2537 题解 观察题目的式子似乎没有什么意义,我们考虑计算出每一种权值的概率 先离散化一下权值 显然可以设一个\(dp\),设\(f[i][j]\)表示\(i\)节点权值为\(j\)的概率 如果\(i\)是叶节点显然 如果\(i\)只有一个儿子直接继承即可 如果\(i\)有两个儿子,对于儿子\(x\),设另一个儿子为\(y\) 则有 \[f[i][j] += f[x][j](1 - p_i)\sum\limits_{k > j}f[r][k] + f[x][j]p_i\sum\

loj#2312. 「HAOI2017」八纵八横(线性基 线段树分治)

题意 题目链接 Sol 线性基+线段树分治板子题.. 调起来有点自闭.. #include<bits/stdc++.h> #define fi first #define se second #define pb push_back #define bit bitset<B + 1> using namespace std; const int MAXN = 501, B = 1001, SS = 4001; inline int read() { char c = getchar

tyvj P2018 「Nescaf&#233;26」小猫爬山 解题报告

P2018 「Nescafé26」小猫爬山 时间: 1000ms / 空间: 131072KiB / Java类名: Main 背景 Freda和rainbow饲养了N只小猫,这天,小猫们要去爬山.经历了千辛万苦,小猫们终于爬上了山顶,但是疲倦的它们再也不想徒步走下山了(呜咕>_<). 描述 Freda和rainbow只好花钱让它们坐索道下山.索道上的缆车最大承重量为W,而N只小猫的重量分别是C1.C2……CN.当然,每辆缆车上的小猫的重量之和不能超过W.每租用一辆缆车,Freda和rainb

「BZOJ4029」[HEOI2015] 定价 贪心

「BZOJ4029」[HEOI2015] 定价 2015年4月28日2,7490 Description 在市场上有很多商品的定价类似于 999 元.4999 元.8999 元这样.它们和 1000 元.5000 元和 9000 元并没有什么本质区别,但是在心理学上会让人感觉便宜很多,因此也是商家常用的价格策略.不过在你看来,这种价格十分荒谬.于是你如此计算一个价格 p(p 为正整数)的荒谬程度: 1.首先将 p 看做一个由数字组成的字符串(不带前导 0): 2.然后,如果 p 的最后一个字符是

Codeforces Round #401 (Div. 2) E 贪心,线段树

Codeforces Round #401 (Div. 2) A 循环节 B 暴力排一下 C 标记出来,但10^5,特耿直地码了个O(n^2)的上去,最气的是在最后3分钟的时候被叉== D 从后往前贪心暴糙一下就好.比赛时一眼瞄出来了不敢写,搞不懂这样竟然不会超时.. E. Hanoi Factory 题意:n个环体,内径a[i],外径b[i],高h[i].当 a[i+1]<b[i]<=b[i+1] 时,第 i 个环体可以堆在第 i+1个环体上.求可以堆出的最高高度. tags:佩服那些大佬,

ACM学习历程——NOJ1113 Game I(贪心 || 线段树)

Description 尼克发明了这样一个游戏:在一个坐标轴上,有一些圆,这些圆的圆心都在x轴上,现在给定一个x轴上的点,保证该点没有在这些圆内(以及圆上),尼克可以以这个点为圆心做任意大小的圆,他想知道自己做多可以与多少个给定的圆相交(相切也算,包含不算). Input 输入有多组数据 输入到文件尾 每一组数据有一个整数n(1<=n<=100000),表示总共有n个圆. 接下是n行,每行两个整数xi,ri表示该圆的圆心坐标和半径. 接下来一行为一个整数x,表示尼克选取点的位置. x xi的范

bzoj 1577: [Usaco2009 Feb]庙会捷运Fair Shuttle【贪心+线段树】

按结束时间排序,然后开个线段树,按照排序后的牛群贪心的选 贪心的依据是选哪头牛都是选,不如给后面的多省一点空间 #include<iostream> #include<cstdio> #include<algorithm> using namespace std; const int N=50005; int m,n,c,ans; struct xds { int l,r,mn,lz; }t[N<<1]; struct qwe { int s,t,m; }a

「Poetize10」能量获取

描述 Description “封印大典启动,请出Nescafe魂珠!”随着 圣主applepi一声令下,圣剑护法rainbow和魔杖护法freda将Nescafe魂珠放置于封印台上.封印台是一个树形的结构,魂珠放置的位置 就是根节点(编号为0).还有n个其它节点(编号1~n)上放置着封印石,编号为i的封印石需要从魂珠上获取Ei的能量.能量只能沿着树边从魂珠传向封印 石,每条边有一个能够传递的能量上限Wi,魂珠的能量是无穷大的.作为封印开始前的准备工作,请你求出最多能满足多少颗封印石的能量需求?