洛谷 P3792 由乃与大母神原型和偶像崇拜
洛谷 P3792 由乃与大母神原型和偶像崇拜
Problem
糖果屋的故事讲的就是韩赛尔和格雷特被继母赶出家里,因为没饭吃了,然后进了森林发现了一个糖果屋,里面有个女巫,专门吃小孩子
然而如果我们仔细想想这个故事,会发现它没有那么简单
比如说,女巫真的是吃小孩子吗?如果女巫是个善良的老婆婆,无偿救助在森林里面困住的小孩子呢?
还有就是当韩赛尔和格雷特杀死了女巫,回到家中发现她们的继母也死了
这是否意味着她们实际上杀死的是她们的继母?
所以这个故事本质上讲的是她们杀了她们的母亲,也就是打败了大母神
很多神话故事里面都有打败大母神的情节
你看到这里也许已经觉得由乃精神不正常了
然而由乃自从不小心##了自己的##后早就不正常了
由乃研究了很久大母神原型,但是仍然一脸懵逼
于是就出数据结构题骗钱去了
由乃:给你一个序列,每次询问一个区间是否是值域连续段
zzy:你把题意说详细点
由乃:就是说不能有重复数字,比如1 2 2 3就不行,然后4 2 3 1就可以
yql:sb分块
ddd:sb bitset
由乃:woc你们好树链啊,我。。我带修
zzq:#######sb题
由乃:我就是要出原题
给你一个长为\(n\)的序列\(a\)
每次两个操作:
- 修改\(x\)位置的值为\(y\)
- 查询区间\([l,r]\)否可以重排为值域上连续的一段
如果可以,输出“damushen”
否则输出“yuanxing”
对于\(100\%\)的数据,\(n,m \le 500000\)
初始值的值域小于\(2.5\times 10^7\),修改操作的\(y\)小于等于\(n\)。
Solution
没有想到什么正解(其实是我不会证),但是可以用区间\(hash\)的思想。
请问,给你一段数字的某些特征信息,如何得之,它是不是连续值域段?
既然是值域连续段,那么首先就要值域等于其极差+1:
- \(len=max-min+1\)
这里我们需要维护\(max\)和\(min\).
然后呢,这一段当然是个公差为1的等差数列,当然满足等差数列的求和公式:
- \(sum=(min+max)*(max-min+1)/2\)
这里我们要维护\(sum\).
再然后呢,是不是还有点不放心?我们再维护一个区间平方和(记为\(pow2\)好了)。这里要先知道,\(\sum_{i=1}^ni^2=\frac n6\times(n+1)\times(2\times n+1)\).这是一个前缀和的形式,使用的时候差分即可。
到这里,已经可以AC这道题啦!但是如果还是不放心,可以再维护一个立方和(记为\(cub\))。使用公式\(\sum_{i=1}^ni^3=(\sum_{i=1}^ni)^2=\frac{(1+n)^2\times n^2}4\).同上差分即可。
欸?这个数字这么大,会不会溢出?
我这里用\(\text{unsigned long long}\)自然溢出。当然您也可以取模(但是有点慢)。
注意,在模意义下就不能用除法了。但是可以将除法移到等式的另一边去就变成了乘法,可以愉快的比较啦!
Code
/**************************************************************
* Problem: 3792
* Author: Vanilla_chan
* Date: 20210321
* E-Mail: Vanilla_chan@outlook.com
**************************************************************/
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<string>
#include<cstring>
#include<cmath>
#include<map>
#include<set>
#include<queue>
#include<vector>
#include<limits.h>
#define IL inline
#define re register
#define LL unsigned long long
#define ULL unsigned long long
//#define int ULL
#ifdef TH
#define debug printf("Now is %d\n",__LINE__);
#else
#define debug
#endif
#ifdef ONLINE_JUDGE
char buf[1<<23],* p1=buf,* p2=buf,obuf[1<<23],* O=obuf;
#define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++)
#endif
using namespace std;
namespace oi
{
inline bool isdigit(const char& ch)
{
return ch<='9'&&ch>='0';
}
inline bool isalnum(const char& ch)
{
return (ch>='a'&&ch<='z')||(ch>='A'&&ch<='Z')||(ch>='0'&&ch<='9');
}
struct istream
{
char ch;
bool fu;
template<class T>inline istream& operator>>(T& d)
{
fu=d=0;
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=1,ch=getchar();
d=ch-'0';ch=getchar();
while(isdigit(ch))
d=(d<<3)+(d<<1)+(ch^'0'),ch=getchar();
if(fu) d=-d;
return *this;
}
inline istream& operator>>(string& str)
{
str.clear();
for(;!isdigit(ch);ch=getchar());
while(isalnum(ch))
str+=ch,ch=getchar();
return *this;
}
}cin;
inline int read()
{
int x=0,fu=1;
char ch=getchar();
while(!isdigit(ch)&&ch!='-') ch=getchar();
if(ch=='-') fu=-1,ch=getchar();
x=ch-'0';ch=getchar();
while(isdigit(ch)) { x=x*10+ch-'0';ch=getchar(); }
return x*fu;
}
int G[55];
template<class T>inline void write(T x)
{
int g=0;
if(x<0) x=-x,putchar('-');
do { G[++g]=x%10;x/=10; } while(x);
for(int i=g;i>=1;--i)putchar('0'+G[i]);putchar('\n');
}
};
using namespace oi;
#define N 500010
int n,m;
int a[N];
struct node
{
int l,r,mx,mn;
ULL sum,pow2,cub;
#define l(x) b[x].l
#define r(x) b[x].r
#define mx(x) b[x].mx
#define mn(x) b[x].mn
#define sum(x) b[x].sum
#define pow2(x) b[x].pow2
#define cub(x) b[x].cub
}b[N*4];
void upd(int p)
{
mx(p)=max(mx(p<<1),mx(p<<1|1));
mn(p)=min(mn(p<<1),mn(p<<1|1));
sum(p)=sum(p<<1)+sum(p<<1|1);
pow2(p)=pow2(p<<1)+pow2(p<<1|1);
cub(p)=cub(p<<1)+cub(p<<1|1);
}
void build(int p,int l,int r)
{
l(p)=l;
r(p)=r;
if(l==r)
{
cub(p)=pow2(p)=sum(p)=mx(p)=mn(p)=a[l];
pow2(p)*=pow2(p);
cub(p)*=pow2(p);
return;
}
int mid=l+r>>1;
build(p<<1,l,mid);
build(p<<1|1,mid+1,r);
upd(p);
}
void change(int p,int x,int k)
{
if(l(p)==r(p))
{
cub(p)=pow2(p)=sum(p)=mx(p)=mn(p)=a[x]=k;
pow2(p)*=pow2(p);
cub(p)*=pow2(p);
return;
}
int mid=l(p)+r(p)>>1;
if(x<=mid) change(p<<1,x,k);
else change(p<<1|1,x,k);
upd(p);
}
int ask_mx(int p,int l,int r)
{
if(l<=l(p)&&r(p)<=r)
{
return mx(p);
}
int mid=l(p)+r(p)>>1;
if(r<=mid) return ask_mx(p<<1,l,r);
if(l>mid) return ask_mx(p<<1|1,l,r);
return max(ask_mx(p<<1,l,r),ask_mx(p<<1|1,l,r));
}
int ask_mn(int p,int l,int r)
{
if(l<=l(p)&&r(p)<=r)
{
return mn(p);
}
int mid=l(p)+r(p)>>1;
if(r<=mid) return ask_mn(p<<1,l,r);
if(l>mid) return ask_mn(p<<1|1,l,r);
return min(ask_mn(p<<1,l,r),ask_mn(p<<1|1,l,r));
}
ULL ask_sum(int p,int l,int r)
{
if(l<=l(p)&&r(p)<=r)
{
return sum(p);
}
int mid=l(p)+r(p)>>1;
if(r<=mid) return ask_sum(p<<1,l,r);
if(l>mid) return ask_sum(p<<1|1,l,r);
return ask_sum(p<<1,l,r)+ask_sum(p<<1|1,l,r);
}
ULL ask_pow(int p,int l,int r)
{
if(l<=l(p)&&r(p)<=r)
{
return pow2(p);
}
int mid=l(p)+r(p)>>1;
if(r<=mid) return ask_pow(p<<1,l,r);
if(l>mid) return ask_pow(p<<1|1,l,r);
return ask_pow(p<<1,l,r)+ask_pow(p<<1|1,l,r);
}
ULL ask_cub(int p,int l,int r)
{
if(l<=l(p)&&r(p)<=r)
{
return cub(p);
}
int mid=l(p)+r(p)>>1;
if(r<=mid) return ask_cub(p<<1,l,r);
if(l>mid) return ask_cub(p<<1|1,l,r);
return ask_cub(p<<1,l,r)+ask_cub(p<<1|1,l,r);
}
ULL mx,mn;
ULL sum;
signed main()
{
//freopen(".in","r",stdin);
//freopen(".out","w",stdout);
n=read();
m=read();
for(int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
int l,r,op;
while(m--)
{
op=read();
l=read();
r=read();
if(op==1)
{
change(1,l,r);
}
else
{
mx=ask_mx(1,l,r);
mn=ask_mn(1,l,r);
if(mx-mn!=r-l)
{
cout<<"yuanxing"<<endl;
continue;
}
if(ask_sum(1,l,r)*2!=(mn+mx)*(mx-mn+1))
{
cout<<"yuanxing"<<endl;
continue;
}
if(ask_pow(1,l,r)*6!=(mx*(mx+1)*(2*mx+1))-(mn*(mn-1)*(2*mn-1)))
{
cout<<"yuanxing"<<endl;
continue;
}
if(ask_cub(1,l,r)*4!=(1+mx)*(1+mx)*mx*mx-mn*mn*(mn-1)*(mn-1))
{
cout<<"yuanxing"<<endl;
continue;
}
cout<<"damushen"<<endl;
}
}
return 0;
}
如果不要立方和的判断的话可以稳过。
加上立方和,稍有些不稳定(或者说是洛谷评测姬不稳定?)。