https://daniu.luogu.org/problemnew/show/P3792
题意提要
给你一个序列a
每次两个操作:
1.修改x位置的值为y
2.查询区间l,r是否可以重排为值域上连续的一段
输入输出格式
输入格式:
第一行两个数n,m
第二行n个数表示a[i]
后面m行每行三个数opt x y,或者opt l r,代表操作
输出格式:
如果可以,输出“damushen”
否则输出“yuanxing”
输入输出样例
输入样例#1: 复制
5 5 1 2 3 4 5 2 1 5 2 2 3 2 3 3 1 3 6 2 3 5
输出样例#1: 复制
damushen damushen damushen damushen
说明
对于30%的数据,n,m<=500
对于60%的数据,n,m<=100000
对于100%的数据,n,m<=500000
值域1e9
2s
思路
使用线段树,维护最大值,最小值,平方和,乘积;
对于一段区间如果(最大值-最小值==区间长度-1)&&(平方和or乘积==合法序列的平方和or乘积(这两个是等价的,为什么都用,hash碰撞QUQ)),
那么该区间合法。
代码实现
1 #include<cstdio> 2 #include<algorithm> 3 const int maxn=1e6+10; 4 const int mod=998244353; 5 inline int min_(int x,int y){return x<y?x:y;} 6 inline int max_(int x,int y){return x>y?x:y;} 7 int n,m; 8 int f[maxn<<2],g[maxn<<2],s[maxn],x[maxn],opt[maxn]; 9 int in[maxn<<2],ax[maxn<<2],ip[maxn<<2],iq[maxn<<2]; 10 struct nate{int x,ip;}dtt[maxn]; 11 bool comp(nate a,nate b){return a.x>b.x;} 12 int FP(int x,int y){ 13 int now=1; 14 while(y){ 15 if(y&1) now=(1ll*now*x)%mod; 16 x=(1ll*x*x)%mod; 17 y>>=1; 18 } 19 return now; 20 } 21 int IE(int x){return FP(x,mod-2);} 22 void build(int k,int l,int r){ 23 if(l==r){ 24 in[k]=ax[k]=s[l]; 25 iq[k]=s[l]; 26 ip[k]=(1ll*s[l]*s[l])%mod; 27 return; 28 } 29 int mid=l+r>>1,ls=k<<1,rs=ls|1; 30 build(ls,l,mid); 31 build(rs,mid+1,r); 32 in[k]=min_(in[ls],in[rs]); 33 ax[k]=max_(ax[ls],ax[rs]); 34 iq[k]=(1ll*iq[ls]*iq[rs])%mod; 35 ip[k]=(1ll*ip[ls]+ip[rs])%mod; 36 } 37 void change(int k,int l,int r,int ap,int at){ 38 if(l==r){ 39 in[k]=ax[k]=ip[k]=at; 40 iq[k]=at; 41 ip[k]=(1ll*at*at)%mod; 42 return; 43 } 44 int mid=l+r>>1,ls=k<<1,rs=ls|1; 45 if(ap<=mid) change(ls,l,mid,ap,at); 46 else change(rs,mid+1,r,ap,at); 47 in[k]=min_(in[ls],in[rs]); 48 ax[k]=max_(ax[ls],ax[rs]); 49 iq[k]=(1ll*iq[ls]*iq[rs])%mod; 50 ip[k]=(1ll*ip[ls]+ip[rs])%mod; 51 } 52 int xin,xax,xip,xiq,bj; 53 void search(int k,int l,int r,int al,int ar){ 54 if(l==al&&r==ar){ 55 xin=min_(xin,in[k]); 56 xax=max_(xax,ax[k]); 57 xip=(1ll*xip+ip[k])%mod; 58 xiq=(1ll*xiq*iq[k])%mod; 59 return; 60 } 61 int mid=l+r>>1,ls=k<<1,rs=ls|1; 62 if(al<=mid) search(ls,l,mid,al,min_(ar,mid)); 63 if(ar>mid) search(rs,mid+1,r,max_(al,mid+1),ar); 64 } 65 bool ok(int l,int r){ 66 xin=mod,xax=0,xip=0,xiq=1; 67 search(1,1,n,l,r); 68 if(xax-xin!=r-l) return 0; 69 bj=(1ll*f[xax]-f[xin-1]+mod)%mod; 70 if(bj!=xip) return 0; 71 bj=(1ll*g[xax]*IE(g[xin-1]))%mod; 72 if(bj!=xiq) return 0; 73 return 1; 74 } 75 int main(){ 76 scanf("%d%d",&n,&m); 77 for(int i=1;i<=n;i++){ 78 scanf("%d",&s[i]); 79 dtt[i].x=s[i],dtt[i].ip=i; 80 } 81 for(int i=1;i<=m;i++){ 82 scanf("%d%d%d",&opt[i],&x[i],&s[n+i]); 83 if(opt[i]==1) dtt[n+i].x=s[n+i],dtt[n+i].ip=n+i; 84 } 85 int top=1;g[0]=1; 86 std::sort(dtt+1,dtt+n+m+1,comp); 87 for(int i=1;dtt[i].x&&i<=n+m;i++){ 88 s[dtt[i].ip]=top; 89 if(dtt[i+1].x==dtt[i].x-1) top++; 90 if(dtt[i+1].x<dtt[i].x-1) top+=2; 91 } 92 for(int i=1;i<=top;i++) g[i]=(1ll*i*g[i-1])%mod; 93 for(int i=1;i<=top;i++) f[i]=(1ll*i*i+f[i-1])%mod; 94 build(1,1,n); 95 for(int i=1;i<=m;i++){ 96 if(opt[i]==1) change(1,1,n,x[i],s[n+i]); 97 else{ 98 if(ok(x[i],s[n+i])) puts("damushen"); 99 else puts("yuanxing"); 100 } 101 } 102 return 0; 103 }
听说是套路题QUQ果然我做题太少了。。。