「
「
「数据结构
」
」
」第
4
4
4章 线段树
(
(
(后
2
2
2题
)
)
)
目录:
D.维护序列
E.字符串排序
大家好 我是个菜鸡 我非常喜欢暴力数据结构 于是我用线段树过了这些题(
D . D. D. 例题 4 4 4 维护序列
洛谷
l
i
n
k
1
link1
link1 洛谷
l
i
n
k
2
link2
link2
分析:
和例题
2
2
2差不多 就是加了个乘操作
但要注意 维护
l
a
z
y
lazy
lazy标记 和下传时 先乘再加
因为 如果维护的是
a
a
a
l
a
z
y
lazy
lazy标记有
+
c
+c
+c和
×
b
\times b
×b
但是
a
×
b
+
c
≠
(
a
+
c
)
×
b
a\times b+c≠(a+c)\times b
a×b+c=(a+c)×b
那维护
l
a
z
y
lazy
lazy标记时 乘和加放在一起 就不知道谁先谁后了
当先加后乘
:
(
a
+
c
)
×
b
=
a
×
b
+
c
×
b
:(a+c)\times b=a\times b+c\times b
:(a+c)×b=a×b+c×b
先乘后加
:
a
×
b
+
c
:a\times b+c
:a×b+c
也就是 先维护乘后加 再
×
\times
×一个
b
b
b 就可以再维护先加后乘了
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e5+5;
struct Seg{
ll sum,lazyA,lazyT;
}tree[N<<2];
int n,q,a[N],mod;
void up(int x){tree[x].sum=(tree[x<<1].sum+tree[x<<1|1].sum)%mod;}
void down(int x,int l,int r)
{
tree[x<<1].lazyT=(tree[x<<1].lazyT*tree[x].lazyT)%mod;
tree[x<<1].lazyA=(tree[x<<1].lazyA*tree[x].lazyT)%mod;
tree[x<<1].sum=(tree[x<<1].sum*tree[x].lazyT)%mod;
tree[x<<1|1].lazyT=(tree[x<<1|1].lazyT*tree[x].lazyT)%mod;
tree[x<<1|1].lazyA=(tree[x<<1|1].lazyA*tree[x].lazyT)%mod;
tree[x<<1|1].sum=(tree[x<<1|1].sum*tree[x].lazyT)%mod;
tree[x].lazyT=1;int mid=(l+r)>>1;
tree[x<<1].lazyA=(tree[x<<1].lazyA+tree[x].lazyA)%mod;
tree[x<<1].sum=(tree[x<<1].sum+tree[x].lazyA*(mid-l+1)%mod)%mod;
tree[x<<1|1].lazyA=(tree[x<<1|1].lazyA+tree[x].lazyA)%mod;
tree[x<<1|1].sum=(tree[x<<1|1].sum+tree[x].lazyA*(r-(mid+1)+1)%mod)%mod;
tree[x].lazyA=0;
}
void build(int x,int l,int r)
{
tree[x].lazyT=1;
if(l==r){
tree[x].sum=a[l]%mod;
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
up(x);
}
void times(int x,int l,int r,int L,int R,int value)
{
if(L<=l&&r<=R)
{
tree[x].sum=(tree[x].sum*value)%mod;
tree[x].lazyA=(tree[x].lazyA*value)%mod;
tree[x].lazyT=(tree[x].lazyT*value)%mod;
return;
}
down(x,l,r);
int mid=(l+r)>>1;
if(L<=mid) times(x<<1,l,mid,L,R,value);
if(mid<R) times(x<<1|1,mid+1,r,L,R,value);
up(x);
}
void add(int x,int l,int r,int L,int R,int value)
{
if(L<=l&&r<=R)
{
tree[x].sum=(tree[x].sum+value*(r-l+1)%mod)%mod;
tree[x].lazyA=(tree[x].lazyA+value)%mod;
return;
}
down(x,l,r);
int mid=(l+r)>>1;
if(L<=mid) add(x<<1,l,mid,L,R,value);
if(mid<R) add(x<<1|1,mid+1,r,L,R,value);
up(x);
}
ll query(int x,int l,int r,int L,int R)
{
if(L<=l&&r<=R) return tree[x].sum;
down(x,l,r);
int mid=(l+r)>>1;
ll ans=0;
if(L<=mid) ans=(ans+query(x<<1,l,mid,L,R))%mod;
if(mid<R) ans=(ans+query(x<<1|1,mid+1,r,L,R))%mod;
return ans;
}
int main()
{
scanf("%d%d",&n,&mod);
for(int i=1;i<=n;i++)
scanf("%d",&a[i]);
build(1,1,n);
scanf("%d",&q);
while(q--)
{
int kd,x,y,val;
scanf("%d",&kd);
if(kd==1)
{
scanf("%d%d%d",&x,&y,&val);
times(1,1,n,x,y,val);
}
if(kd==2){
scanf("%d%d%d",&x,&y,&val);
add(1,1,n,x,y,val);
}
if(kd==3){
scanf("%d%d",&x,&y);
printf("%lld\n",query(1,1,n,x,y));
}
}
return 0;
}
E . E. E. 例题 5 5 5 字符串排序
L
u
o
g
u
Luogu
Luogu
l
i
n
k
link
link
分析:
线段树
每个叶子节点就是对应字符的值
维护区间
[
l
,
r
]
[l,r]
[l,r] 中各个字符的次数
然后 分别按升序或降序 依次替换线段树中的位置
CODE:
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
#include<cmath>
#include<queue>
#include<vector>
#include<bitset>
#define Ctnue continue
//#pragma GCC optimize(2)
#define reg register
using namespace std;
typedef long long ll;
typedef double db;
typedef unsigned long long ull;
const int N=1e5+5;
struct node{
int l,r,val;
}tree[N<<2];
char s[N];
int n,m,len[27];
void build(int x,int l,int r)
{
tree[x].l=l;tree[x].r=r;
if(l==r){
tree[x].val=s[l]-'a'+1;
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
if(tree[x<<1].val==tree[x<<1|1].val) tree[x].val=tree[x<<1].val;
}
void update(int x,int l,int r)
{
if(l<=tree[x].l&&tree[x].r<=r&&tree[x].val!=0)
{
len[tree[x].val]+=tree[x].r-tree[x].l+1;
return;
}
if(tree[x].val){
tree[x<<1].val=tree[x].val;
tree[x<<1|1].val=tree[x].val;
}
int mid=(tree[x].l+tree[x].r)>>1;
if(l<=mid) update(x<<1,l,r);
if(mid<r) update(x<<1|1,l,r);
}
void query(int x,int l,int r,int val)
{
if(l<=tree[x].l&&tree[x].r<=r)
{
tree[x].val=val;
return;
}
if(tree[x].val){
tree[x<<1].val=tree[x].val;
tree[x<<1|1].val=tree[x].val;
tree[x].val=0;
}
int mid=(tree[x].l+tree[x].r)>>1;
if(l<=mid) query(x<<1,l,r,val);
if(mid<r) query(x<<1|1,l,r,val);
if(tree[x<<1].val==tree[x<<1|1].val) tree[x].val=tree[x<<1].val;
}
void print(int x)
{
if(tree[x].val)
{
int lenth=tree[x].r-tree[x].l+1;
for(int i=1;i<=lenth;i++)
putchar(tree[x].val+'a'-1);
return;
}
print(x<<1);print(x<<1|1);
}
int main()
{
scanf("%d%d",&n,&m);
scanf("%s",s+1);
build(1,1,n);
while(m--)
{
int l,r,op;
scanf("%d%d%d",&l,&r,&op);
memset(len,0,sizeof(len));
update(1,l,r);
if(op==1){
for(int i=1;i<=26;i++)
if(len[i]){
query(1,l,l+len[i]-1,i);
l+=len[i];
}
}
if(op==0){
for(int i=26;i>=1;i--)
if(len[i]){
query(1,l,l+len[i]-1,i);
l+=len[i];
}
}
}
print(1);
return 0;
}