背景:
无…
题目传送门:
https://www.luogu.org/problemnew/show/P3792
题意:
n
n
n个数,若干组询问,每一次询问
[
l
,
r
]
[l,r]
[l,r]中是否经过排序可以形成值域严格上升的序列。
思路:
显然用分块的思想(记录上一个和当前相等的数是否在当前块外)很容易实现,参见HH的项链(有些类似,好像不是一回事,但我找不到之前做的这样的题了) 。
但时间复杂度却承受不了。
于是想到了线段树来维护,那么时间复杂度降为了 Θ ( n l o g 2 n ) \Theta(nlog^2n) Θ(nlog2n)。
还是不对劲。
想不到了。
于是翻了题解。暴怒。 原来用
h
a
s
h
hash
hash的思想,开一棵线段树维护区间最大值,最小值,平方和(当然用立方和更好,但值域太大,我放弃了)。
那么,对于一段区间
[
l
,
r
]
[l,r]
[l,r],记最大值为
M
a
x
Max
Max,最小值为
M
i
n
Min
Min,平方和为
S
u
m
Sum
Sum,必然存在
r
−
l
=
M
a
x
−
M
i
n
r-l=Max-Min
r−l=Max−Min,且
∑
i
=
m
i
n
M
a
x
i
2
=
S
u
m
\sum^{Max}_{i=min}i^2=Sum
∑i=minMaxi2=Sum。
但这不能保证
100
%
100\%
100%正确。
反例如下:
example:
9 1
1 2 3 4 5 2 9 8 9
2 1 9
correct answer:yuanxing
wrong answer:damushen
因此用三次方能更好的避免冲突。
但是值域为
1
0
9
10^9
109,很难接受,我还是放弃了。
有一点,在求
∑
i
=
m
i
n
M
a
x
i
2
\sum^{Max}_{i=min}i^2
∑i=minMaxi2的时候会爆
l
o
n
g
l
o
n
g
long\ long
long long,因此无法用前缀和+数学推导来求,按照题解的说法,改用循环求解,不会超时。
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#define LL long long
#define INF (int)(1e9)+1
using namespace std;
struct node{int l,r,lc,rc,mi,ma;LL sum;} tr[1000010];
int n,m,len=0;
void build(int l,int r)
{
int now=++len,mid=(l+r)>>1;
tr[now]=(node){l,r,-1,-1,INF,-INF,0};
if(l<r)
{
tr[now].lc=len+1; build(l,mid);
tr[now].rc=len+1; build(mid+1,r);
}
}
void change(int now,int l,int r,int k)
{
if(l==tr[now].l&&r==tr[now].r)
{
tr[now].ma=tr[now].mi=k;
tr[now].sum=(LL)k*k;
return;
}
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) change(lc,l,r,k);
else if(l>mid) change(rc,l,r,k);
else change(lc,l,mid,k),change(rc,mid+1,r,k);
tr[now].ma=max(tr[lc].ma,tr[rc].ma);
tr[now].mi=min(tr[lc].mi,tr[rc].mi);
tr[now].sum=tr[lc].sum+tr[rc].sum;
}
node find(int now,int l,int r)
{
if(l==tr[now].l&&r==tr[now].r) return tr[now];
int lc=tr[now].lc,rc=tr[now].rc,mid=(tr[now].l+tr[now].r)>>1;
if(r<=mid) return find(lc,l,r);
else if(l>mid) return find(rc,l,r);
else
{
node tmp,tmp1=find(lc,l,mid),tmp2=find(rc,mid+1,r);
tmp.ma=max(tmp1.ma,tmp2.ma);
tmp.mi=min(tmp1.mi,tmp2.mi);
tmp.sum=tmp1.sum+tmp2.sum;
return tmp;
}
}
LL calc(int x,int y)
{
LL sum=0;
for(int i=x;i<=y;i++)
sum+=(LL)i*i;
return sum;
}
bool work(int x,int y)
{
node ans=find(1,x,y);
int t1=ans.mi,t2=ans.ma;
if(y-x!=t2-t1) return false;
return calc(t1,t2)==ans.sum;
}
int main()
{
int t,x,y;
scanf("%d %d",&n,&m);
build(1,n);
for(int i=1;i<=n;i++)
{
scanf("%d",&x);
change(1,i,i,x);
}
for(int i=1;i<=m;i++)
{
scanf("%d %d %d",&t,&x,&y);
switch(t)
{
case 1:change(1,x,x,y);break;
case 2:printf(work(x,y)?"damushen\n":"yuanxing\n");break;
}
}
}