CSUST 4005-你真的会!(分治思维+线段树)

题目链接:http://acm.csust.edu.cn/problem/4005
博客园食用链接:https://www.cnblogs.com/lonely-wind-/p/13440076.html

Description

给一个长度 n n 的序列 a i a_i 要进行 m m 次操作,共有三种操作:

1. ( L    R    V ) 1.(L\;R\;V) 表示区间 [ L , R ] [L,R] 数值覆盖为 V V

2. ( P    V ) 2.(P\;V) 表示 a p a_p 数值赋值为 V V

3. ( L    R ) 3.(L\;R) 表示询问询问 f ( L , R ) f(L,R) 的值。

注意:
对于区间 [ L , R ] [L,R] 的数字而言, S i S_i =在区间内任意选ii个数的乘积之和。

f ( L , R ) = ( 1 + i = 1 R L + 1 S i ) m o d    1 e 9 + 9 f(L,R)=(1+\sum_{i=1}^{R-L+1}S_i)mod\; 1e9+9

Input
一行两个整数 n , m ( 1 n , m 2 e 5 ) n,m(1\le n,m\le 2e5)

接下来一行 n n 个整数表示 a i ( 0 a i 1 e 9 ) a_i(0\le a_i\le 1e9)

接下来 m m 行表示 m m 次操作:

输入格式为:

1    L    R    V , 1 L R n , 0 V 1 e 9 1\;L\;R\;V, 1\le L\le R\le n, 0\le V\le 1e9
2    P    V , 1 P n , 0 V 1 e 9 2\;P\;V,1\le P\le n,0\le V\le 1e9
3    L    R , ( 1 L R n ) 3\;L\;R,(1\le L\le R\le n)

Output
对每次 3 3 号操作输出一行一个整数表示答案。答案要对 1 e 9 + 9 1e9+9 取模。

emmm,说是个签到题来着。。。如果单纯地盯着上面的 f ( L , R ) = ( 1 + i = 1 R L + 1 S i ) m o d    1 e 9 + 9 f(L,R)=(1+\sum_{i=1}^{R-L+1}S_i)mod\; 1e9+9 这一串式子,肯定是没有什么眉目的,我们看题目要求应该大概是个线段树,那么我们只需要考虑的是在线段树中将两颗子树合并后的结果和区间覆盖后的结果。那么对于每个节点,我们保存的值假设就是 v a l + 1 val+1 ,那么我们考虑合并 x , y x,y 两个值,他们合并之后就是 x y + x + y + 1 xy+x+y+1 ,可以看出就是两个数相乘加上两个数相加,那么似乎就是 ( x + 1 ) ( y + 1 ) (x+1)*(y+1) ,于是我们会惊讶地发现父节点的值就是两个儿子节点的乘积!

接下来就是对于区间覆盖的处理了,那么就相当于 r l + 1 r-l+1 x x 的合并,那么就是 ( x + 1 ) r l + 1 (x+1)^{r-l+1} 。似乎这题就结束了。

以下是AC代码:

#include <bits/stdc++.h>
using namespace std;

#define lson l,mid,rt<<1
#define rson mid+1,r,rt<<1|1
#define lc rt<<1
#define rc rt<<1|1
typedef long long ll;
const int mac=2e5+10;
const int mod=1e9+9;

ll tree[mac<<2],lazy[mac<<2];

ll qpow(ll a,ll b)
{
	ll ans=1; a%=mod;
	while (b){
		if (b&1) ans=ans*a%mod;
		a=a*a%mod;
		b>>=1;
	}
	return ans;
}

void build(int l,int r,int rt)
{
	lazy[rt]=-1;
	if (l==r) {
		scanf ("%d",&tree[rt]);
		tree[rt]++;
		return;
	}
	int mid=(l+r)>>1;
	build(lson); build(rson);
	tree[rt]=tree[lc]*tree[rc]%mod;
}

void push_down(int l,int r,int rt)
{
	int mid=(l+r)>>1;
	lazy[lc]=lazy[rt]; lazy[rc]=lazy[rt];
	tree[lc]=qpow(lazy[rt],mid-l+1);  tree[rc]=qpow(lazy[rt],r-mid);
	lazy[rt]=-1;
}

void update(int l,int r,int rt,int L,int R,int val)
{
	if (l>=L && r<=R) {
		lazy[rt]=val+1;
		tree[rt]=qpow(val+1,r-l+1);
		return;
	}
	int mid=(l+r)>>1;
	if (lazy[rt]!=-1) push_down(l,r,rt);
	if (mid>=L) update(lson,L,R,val);
	if (mid<R) update(rson,L,R,val);
	tree[rt]=tree[lc]*tree[rc]%mod;
}

ll query(int l,int r,int rt,int L,int R)
{
	ll ans=1;
	if (l>=L && r<=R) {return tree[rt];}
	int mid=(l+r)>>1;
	if (lazy[rt]!=-1) push_down(l,r,rt);
	if (mid>=L) ans=ans*query(lson,L,R)%mod;
	if (mid<R) ans=ans*query(rson,L,R)%mod;
	return ans;
}

int main(int argc, char const *argv[])
{
	int n,m;
	scanf ("%d%d",&n,&m);
	build(1,n,1);
	while (m--){
		int opt,l,r,v,pos;
		scanf ("%d",&opt);
		if (opt==1){
			scanf ("%d%d%d",&l,&r,&v);
			update(1,n,1,l,r,v);
		}
		else if (opt==2){
			scanf ("%d%d",&pos,&v);
			update(1,n,1,pos,pos,v);
		}
		else {
			scanf ("%d%d",&l,&r);
			printf("%lld\n",query(1,n,1,l,r));
		}
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_43906000/article/details/107815634