爱狗人士不喜猫树

137 篇文章 1 订阅
11 篇文章 0 订阅

题目

题目描述
有这样一道猫树的板题:

给出长度为 n n n 的序列 a a a,定义 c o s t ( l , r ) = ( max ⁡ i = l r a i ) ⋅ ( min ⁡ i = l r a i ) cost(l,r)=(\max_{i=l}^{r}a_i)\cdot(\min_{i=l}^ra_i) cost(l,r)=(maxi=lrai)(mini=lrai),多次询问,回答 ∑ l = L R ∑ r = l R c o s t ( l , r )   m o d   ( 1 0 9 + 7 ) \sum_{l=L}^{R}\sum_{r=l}^{R}cost(l,r)\bmod(10^9+7) l=LRr=lRcost(l,r)mod(109+7) 的结果。

但是 F i r e W i n g B i r d \sf FireWingBird FireWingBird 非常气愤!这是种族之间的深仇大恨。

所以它决定出数据卡掉猫树的 O ( n log ⁡ 2 n ) \mathcal O(n\log^2n) O(nlog2n) 做法。

但是 s t d \rm std std 还是要给的啊。你能不能帮助 F i r e W i n g B i r d \sf FireWingBird FireWingBird 写一个标算呢?

数据范围与提示
n ⩽ 1 0 5 n\leqslant 10^5 n105,序列的元素满足 1 ⩽ a i ⩽ 1 0 9 1\leqslant a_i\leqslant 10^9 1ai109

思路

就只说一点:区间乘和区间 “赋值” 到底谁简单?这可说不好。

用一个线段树,维护 r r r 为某个值时的 c o s t ( l , r ) cost(l,r) cost(l,r) 。两个单调栈,分别维护 min ⁡ \min min max ⁡ \max max 。这里一定要选用 区间乘,因为单独对 min ⁡ \min min 或者 max ⁡ \max max 赋值,都很糟糕。而先乘 i n v inv inv 再乘当前值,就简单的一批。

区间乘之后,我们要将权值下放到 l l l 上(历史值求和)。跟此题较为近似,需要打一个标记,表示 “将当前值累加一次”。显然它和前面的区间乘标记需要一同维护,就写一个结构体就行了。

复杂度 O ( n log ⁡ n A + q log ⁡ n q ) \mathcal O(n\log nA+q\log nq) O(nlognA+qlognq)

代码

#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long int_;
# define rep(i,a,b) for(int i=(a); i<=(b); ++i)
# define drep(i,a,b) for(int i=(a); i>=(b); --i)
inline int readint(){
	int a = 0; char c = getchar(), f = 1;
	for(; c<'0'||c>'9'; c=getchar())
		if(c == '-') f = -f;
	for(; '0'<=c&&c<='9'; c=getchar())
		a = (a<<3)+(a<<1)+(c^48);
	return a*f;
}
inline void writeint(int x){
	if(x > 9) writeint(x/10);
	putchar((x-x/10*10)^48);
}

const int Mod = 1e9+7;
inline int qkpow(int_ b,int q){
	int a = 1;
	for(; q; q>>=1,b=b*b%Mod)
		if(q&1) a = a*b%Mod;
	return a;
}
struct Tag{
	// v' = kv * v, his += khis * v
	int kv, khis;
	Tag():kv(1),khis(0){ }
	Tag(int A,int B){
		kv = A, khis = B;
	}
	/// @brief command *this and then @p t
	Tag operator * (const Tag &t) const {
		return Tag(int_(kv)*t.kv%Mod,
			(int_(kv)*t.khis+khis)%Mod);
	}
	Tag& operator *= (const Tag &t){
		return *this = (*this)*t;
	}
	Tag operator + (const Tag &t) const {
		return Tag((kv+t.kv)%Mod,(khis+t.khis)%Mod);
	}
};

const int MaxN = 100005;
int n; // length of segment tree
namespace SgTree{
	Tag val[MaxN<<2], lazy[MaxN<<2];
	void fuck(int o,const Tag &qv){
		val[o] *= qv, lazy[o] *= qv;
	}
	void pushDown(int o){
		rep(d,0,1) fuck(o<<1|d,lazy[o]);
		lazy[o] = Tag(1,0); // useless
	}
	void pushUp(int o){
		val[o] = val[o<<1]+val[o<<1|1];
	}
	# define __ROOT int o=1,int l=1,int r=n
	# define LSON o<<1,l,(l+r)>>1
	# define RSON o<<1|1,((l+r)>>1)+1,r
	void build(__ROOT){
		val[o] = lazy[o] = Tag(1,0);
		if(l != r) build(LSON), build(RSON);
	}
	void modify(int ql,int qr,const Tag &tag,__ROOT){
		if(qr < l || r < ql) return ;
		if(ql <= l && r <= qr) return fuck(o,tag);
		pushDown(o); modify(ql,qr,tag,LSON);
		modify(ql,qr,tag,RSON), pushUp(o);
	}
	int query(int ql,int qr,__ROOT){
		if(qr < l || r < ql) return 0;
		if(ql <= l && r <= qr)
			return val[o].khis;
		pushDown(o);
		int res = query(ql,qr,LSON);
		res += query(ql,qr,RSON);
		if(res >= Mod) res -= Mod;
		return res;
	}
}

struct Query{
	int l, r, id;
	bool operator < (const Query &t) const {
		return r < t.r;
	}
};
Query ask[MaxN];

int mx[MaxN], mn[MaxN], a[MaxN];
int top_mx, top_mn, xyx[MaxN];
int main(){
	n = readint(); int q = readint();
	SgTree::build(); // needed
	rep(i,1,n) a[i] = readint();
	rep(i,1,q){
		ask[i].l = readint();
		ask[i].r = readint();
		ask[i].id = i;
	}
	sort(ask+1,ask+q+1);
	for(int i=1,qid=1; i<=n; ++i){
		while(top_mx && a[mx[top_mx]] < a[i]){
			int inv = qkpow(a[mx[top_mx]],Mod-2); -- top_mx;
			SgTree::modify(mx[top_mx]+1,mx[top_mx+1],Tag(inv,0));
		}
		SgTree::modify(mx[top_mx]+1,i,Tag(a[i],0));
		while(top_mn && a[mn[top_mn]] > a[i]){
			int inv = qkpow(a[mn[top_mn]],Mod-2); -- top_mn;
			SgTree::modify(mn[top_mn]+1,mn[top_mn+1],Tag(inv,0));
		}
		SgTree::modify(mn[top_mn]+1,i,Tag(a[i],0));
		mx[++ top_mx] = mn[++ top_mn] = i;
		SgTree::modify(1,i,Tag(1,1)); // accumulate tag
		for(; qid<=q&&ask[qid].r==i; ++qid)
			xyx[ask[qid].id] = SgTree::query(ask[qid].l,i);
	}
	rep(i,1,q) writeint(xyx[i]), putchar('\n');
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
好的,以下是一个简单的“猫咪窝”介绍网页的示例代码: ```html <!DOCTYPE html> <html> <head> <meta charset="UTF-8"> <title>猫咪窝介绍</title> <style> /* 网页样式 */ body { font-family: Arial, sans-serif; background-color: #f5f5f5; } h1 { text-align: center; } .container { margin: 0 auto; max-width: 800px; padding: 20px; background-color: #fff; box-shadow: 0 0 10px rgba(0, 0, 0, 0.2); } .img-container { display: flex; flex-wrap: wrap; justify-content: center; margin-top: 20px; } .img-container img { width: 250px; height: 250px; margin: 10px; object-fit: cover; border-radius: 50%; box-shadow: 0 0 5px rgba(0, 0, 0, 0.2); } p { line-height: 1.5; text-align: justify; margin-top: 20px; } </style> </head> <body> <div class="container"> <h1>欢迎来到猫咪窝</h1> <div class="img-container"> <img src="https://via.placeholder.com/250x250?text=Cat+1" alt="猫咪1"> <img src="https://via.placeholder.com/250x250?text=Cat+2" alt="猫咪2"> <img src="https://via.placeholder.com/250x250?text=Cat+3" alt="猫咪3"> <img src="https://via.placeholder.com/250x250?text=Cat+4" alt="猫咪4"> <img src="https://via.placeholder.com/250x250?text=Cat+5" alt="猫咪5"> <img src="https://via.placeholder.com/250x250?text=Cat+6" alt="猫咪6"> </div> <p>猫咪窝是一个专门为猫咪打造的网站,提供各种猫咪相关的信息和服务。在这里,你可以找到各种品种的猫咪介绍、照片和视频,了解它们的习性和喜好,还可以分享你的猫咪照片和故事。</p> <p>此外,猫咪窝还提供猫咪用品的购买和租借服务,包括猫粮、猫玩具、猫树等等。无论你是新手还是老手,都可以在猫咪窝找到适合自己的猫咪用品。</p> <p>快来加入我们的猫咪家族吧!</p> </div> </body> </html> ``` 这个网页由一个标题、一组猫咪照片、以及一些介绍文字组成,样式使用了简单的 CSS。你可以将这个代码复制到一个 HTML 文件中,用浏览器打开即可看到效果。当然,如果你有更多的想法,可以自由发挥,加入更多的元素和交互效果。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值