1. 程式人生 > >題解 P3792 【由乃與大母神原型和偶像崇拜】

題解 P3792 【由乃與大母神原型和偶像崇拜】

這題,主要是維護平方和來判斷區間是否連續,但這裡任然有兩個問題:

1.值域為1e9,極限下,long long是一定會爆炸的

2.正如討論區的,平方和可以被hack

那麼該如何解決這個問題呢?

我的想法是——離散化!

離散化後,值域的極限就在1e6,假設這5e5個數,每個都是1e6,平方和也才5e17,long long是不會爆炸的。

離散化後,雖說hack的機率就減小了,但是,為了準確性,我們可以同時再維護個和(我覺得,這樣應該很難被hack了吧。。。)

所以我們完成這題,可以先將原數,以及opt==1時的數字離散化一波,再進行操作!

具體的操作跟其他題解差不多,沒什麼好講的了~(由於本人比較菜,是自己模擬的離散化,勿噴...QwQ)

程式碼如下:

#include<bits/stdc++.h>
using namespace std;
const int N=5e5+1,M=1e3;
struct node{//線段樹維護:和,平方和,區間極值 
    long long s,w,ming,maxe;
}t[N<<2];
struct thing{//離散化陣列 
    int w,num;
}p[N<<1];
int a[N],opt[N],L[N],R[N];
long long mi,mx,S;
inline void build(int now,int l,int r){//建樹 
if(l==r){ t[now].s=a[l]; t[now].w=1LL*a[l]*a[l]; t[now].maxe=t[now].ming=a[l]; return; } int mid=(l+r)>>1; build(now<<1,l,mid),build(now<<1|1,mid+1,r); t[now].s=t[now<<1].s+t[now<<1|1].s; t[now].w=t[now<<1].w+t[now<<1
|1].w; t[now].maxe=max(t[now<<1].maxe,t[now<<1|1].maxe); t[now].ming=min(t[now<<1].ming,t[now<<1|1].ming); } inline void change(int now,int l,int r,int k,int x){//單點修改 if(l==r){ t[now].s=x; t[now].w=1LL*x*x; t[now].ming=t[now].maxe=x; return; } int mid=(l+r)>>1; if(k<=mid){ change(now<<1,l,mid,k,x); } else{ change(now<<1|1,mid+1,r,k,x); } t[now].s=t[now<<1].s+t[now<<1|1].s; t[now].w=t[now<<1].w+t[now<<1|1].w; t[now].maxe=max(t[now<<1].maxe,t[now<<1|1].maxe); t[now].ming=min(t[now<<1].ming,t[now<<1|1].ming); } inline long long find(int now,int l,int r,int lc,int rc){//區間查詢 if(lc<=l&&r<=rc){ S+=t[now].s; mx=max(mx,t[now].maxe); mi=min(mi,t[now].ming); return t[now].w; } int mid=(l+r)>>1; long long sum=0; if(lc<=mid){ sum+=find(now<<1,l,mid,lc,rc); } if(rc>mid){ sum+=find(now<<1|1,mid+1,r,lc,rc); } return sum; } inline long long suan(long long x){ long long sut=(x*(x+1)/2)*(2*x+1)/3; return sut; } inline bool kkk(thing x,thing y){ return x.w<y.w; } int main(){ int n,m; scanf("%d%d",&n,&m); for(int i=1;i<=n;++i){ scanf("%d",&a[i]); p[i].w=a[i],p[i].num=i; } int e=n; for(int i=1;i<=m;++i){ scanf("%d%d%d",&opt[i],&L[i],&R[i]); if(opt[i]==1){ p[++e].w=R[i]; p[e].num=i+n; continue; } } sort(p+1,p+e+1,kkk); int ran=1; if(p[1].num<=n){ a[p[1].num]=1; } else{ R[p[1].num-n]=1; } for(int i=2;i<=e;++i){ if(p[i].w!=p[i-1].w){ ran++; } if(p[i].num<=n){ a[p[i].num]=ran; continue; } R[p[i].num-n]=ran; } build(1,1,n); for(int i=1;i<=m;++i){ if(opt[i]==1){ change(1,1,n,L[i],R[i]); continue; } S=0,mi=2e9,mx=-2e9; long long sum=find(1,1,n,L[i],R[i]);//這樣寫可以只find一次,當然也可以直接返回三元組。。。 if(mx-mi!=R[i]-L[i]){//如果極值之差不等於區間左右端點,則必不連續 puts("yuanxing"); continue; } long long sut=suan(mx)-suan(mi-1);//獲得平方和 if(S!=(mx+mi)*(mx-mi+1)/2||sut!=sum){//比較,若不等,則必不為連續區間 puts("yuanxing"); continue; } puts("damushen"); } return 0; } /** *  ┏┓   ┏┓+ + * ┏┛┻━━━┛┻┓ + + * ┃       ┃ * ┃   ━   ┃ ++ + + + * ████━████+ * ◥██◤ ◥██◤ + * ┃   ┻   ┃ * ┃       ┃ + + * ┗━┓   ┏━┛ *   ┃   ┃ + + + +Code is far away from   *   ┃   ┃ + bug with the animal protecting *   ┃    ┗━━━┓ 神獸保佑,程式碼無bug  *   ┃        ┣┓ *   ┃        ┏┛ *  ┗┓┓┏━┳┓┏┛ + + + + *    ┃┫┫ ┃┫┫ *    ┗┻┛ ┗┻┛+ + + + */