毒瘤(指题目名)

首先如果我们不考虑复杂度的话,直接主席树二分就能轻松解决了

但是3e5的数据范围会让nlog^n的算法跑得很慢,而且常数也比较大

所以我们考虑换一个思路

假如我们从小到大把点按权值排序,然后开始用并查集合并,记录下合并时的位置的值,最左边的位置,以及所在块的权值

接着我们考虑把询问的权值从大到小排序,那么对于每一个询问,就可以把所有权值比他大的合并点都加进来

我们设询问的左端点l作为左边界时,右边界最小为minpos,右端点r作为右边界时,最大的左边界为maxpos;

这两个可以先统计一边贡献,对于之前的每次合并,我们在最左边的位置上修改最小值为合并时位置的值

那么我们查询时只需要查询l到maxpos所对应的最小值就可以了,

可以证明如果多了肯定不优,所以一定正确

别人的代码,我是真的不想写了

#include <bits/stdc++.h>
using namespace std;
typedef long long lnt;
typedef long long ll;
typedef pair<int,int> pii;
const lnt inf  = 2e18;
const int N = 3e5 + 10;
int read() {
	int x = 0;
	char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) x = (x << 1) + (x << 3) + c - '0' , c = getchar();
	return x;
}
lnt readll() {
	lnt x = 0;
	char c = getchar();
	while (!isdigit(c)) c = getchar();
	while (isdigit(c)) x = (x << 1) + (x << 3) + c - '0' , c = getchar();
	return x;
}
void writeln(int x) {
	if (!x) {
		puts("0");
		return;
	}
	int dg[20] , len = 0;

	if (x < 0) x = -x , putchar('-');

	while (x) {
		dg[len++] = x % 10;
		x /= 10;
	}

	while (len--) {
		putchar(dg[len] + '0');
	}
	putchar('\n');
}
struct interval {
	int l , r , maxn;
	lnt sum;
	inline bool operator < (const interval &A) const {
		return sum > A.sum;
	}
};
int n , m , d[N] , rnk[N];
lnt sum[N] , minm[N << 1] , maxn[N << 1];
lnt calc(int l,int r) {
	return (sum[r] - sum[l-1]) * (r - l + 1);
}
void modify(int x,int l,int r,int pos,int v) {
	if (l == r) {
		minm[x] = v;
		return;
	}
	int m = l + r >> 1 , z = x + ((m - l + 1) << 1);
	if (pos <= m) {
		modify(x + 1 , l , m , pos , v);
	} else {
		modify(z , m + 1 , r , pos , v);
	}
	minm[x] = min(minm[x + 1] , minm[z]);
}
int query(int x,int l,int r,int ql,int qr) {
	if (ql <= l && r <= qr) {
		return minm[x];
	}
	int m = l + r >> 1 , z = x + ((m - l + 1) << 1) , res = 1000000000;
	if (ql <= m) res = min(res , query(x + 1 , l , m , ql , qr));
	if (m < qr ) res = min(res , query(z , m + 1 , r , ql , qr));
	return res;
}
void build(int x,int l,int r) {
	minm[x] = 1000000000;
	if (l == r) {
		maxn[x] = d[l];
		return;
	}
	int m = l + r >> 1 , z = x + ((m - l + 1) << 1);
	build(x + 1 , l , m);
	build(z , m + 1 , r);
	maxn[x] = max(maxn[x + 1] , maxn[z]);
}
int querymax(int x,int l,int r,int ql,int qr) {
	if (ql <= l && r <= qr) {
		return maxn[x];
	}
	int m = l + r >> 1 , z = x + ((m - l + 1) << 1) , res = 0;
	if (ql <= m) res = max(res , querymax(x + 1 , l , m , ql , qr));
	if (m < qr ) res = max(res , querymax(z , m + 1 , r , ql , qr));
	return res;
}
vector <interval> v;
set <int> s;
struct Asktion {
	int l , r , id;
	lnt x;
	inline bool operator < (const Asktion &A) const {
		return x > A.x;
	}
};
Asktion asks[N];
int res[N];
int getposl(int l,lnt x) {
	int L = l , R = n  , res = -1;
	while (L <= R) {
		int mid = L + R >> 1;
		if (calc(l , mid) >= x) {
			res = mid;
			R = mid - 1;
		} else {
			L = mid + 1;
		}
	}
	return res;
}
int getposr(int r,lnt x) {
	int L = 1 , R = r  , res = -1;
	while (L <= R) {
		int mid = L + R >> 1;
		if (calc(mid , r) >= x) {
			res = mid;
			L = mid + 1;
		} else {
			R = mid - 1;
		}
	}
	return res;
}
int main() {
	scanf("%d%d",&n,&m);
	for (int i = 1; i <= n; i++) {
		d[i] = read();
		rnk[i] = i;
		sum[i] = sum[i-1] + d[i];
	}
	build(1 , 1 , n);
	sort(rnk + 1 , rnk + 1 + n , [](int a,int b) -> bool {return d[a] > d[b];});
	s.insert(0);
	s.insert(n + 1);
	for (int i = 1; i <= n; i++) {
		s.insert(rnk[i]);
		set<int>::iterator it = s.find(rnk[i]);
		int pre = *(--it) + 1 , nxt = *(++++it) - 1;
		v.push_back((interval) {
			pre , nxt , d[rnk[i]] , 1ll * (nxt - pre + 1) * (sum[nxt] - sum[pre-1])
		});

	}
	sort(v.begin() , v.end());
	for (int i = 1; i <= m; i++) {
		scanf("%d%d%lld",&asks[i].l,&asks[i].r,&asks[i].x);
		asks[i].x = (asks[i].x + 1) >> 1;
		asks[i].id = i;
	}
	sort(asks + 1 , asks + 1 + m);
	int now = -1;
	for (int i = 1; i <= m; i++) {
		while (now + 1 < (int) v.size() && v[now + 1].sum  >= asks[i].x) {
			now++;
			modify(1 , 1 , n , v[now].l , v[now].maxn);
		}
		int l = asks[i].l , r = asks[i].r , L = getposl(l , asks[i].x) , R = getposr(r , asks[i].x);

		if (L == -1 || L > r) {
			res[asks[i].id] = -1;
			continue;
		}
		res[asks[i].id] = min( query(1 , 1 , n , l , R) , min(querymax(1 , 1 , n , l , L) , querymax(1 , 1 , n , R , r) ) );
	}
	for (int i = 1; i <= m; i++) printf("%d ",res[i]);
	return 0;
}

 

T23713 [愚人节题目2]数据结构大毒瘤 提交答案加入题单复制题目 提交 1.47k 通过 273 时间限制 1.00s 内存限制 125.00MB 题目编号 T23713 提供者 洛谷官方团队 难度 暂无评定 历史分数 暂无 提交记录 标签 洛谷原创 推荐题目 暂无 复制 Markdown 展开 进入 IDE 模式 题目背景 这是一道毒瘤题 这题太难了,所以窝先卖个萌0=w=0 窝从没出过这么难的题!!!! 题目描述 你好啊~这是一道数据结构毒瘤题~ 您需要维护一个数列S~ 有7种操作,形如w a b c w=0 输出S a ​ +S a+1+...+S b ​ 。c没有用 w=1 将[S a ​ ,S b ​ ]翻转。c没有用 w=2 将[S a ​ ,S b ​ ]内的数全部加上c。 w=3 将[S a ​ ,S b ​ ]内的数全部乘上c。 w=4 将[S a ​ ,S b ​ ]内的数全部开根号。c没有用 w=5 将S a ​ 加上c,将S a+1 ​ 加上2c,...,将S b ​ 加上c*(b-a+1) w=6 将[S a ​ ,S b ​ ]和[S b+1 ​ ,S c ​ ]交换。保证c-b=b-a+1。 输入格式 第一行是n和m,n表示初始序列的长度,m表示操作数量 然后n个整数,表示初始序列S 之后m行每行四个数w a b c,代表一个操作 输出格式 对于每个0操作,输出一行表示答案 输入输出样例 输入 #1复制 5 1 1 2 3 4 5 0 1 2 3 输出 #1复制 3 说明/提示 样例解释 第一次操作,询问的答案为1+2=3 数据范围 1≤n,m≤5×10 4 ,0≤w≤9,1≤a≤b≤n 保证任何时候S i ​ ∈[−10 9 ,10 9 ] 保证输入所有数∈[−10 9 ,10 9 ]
最新发布
07-19
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值