gym102798 Caesar Cipher (2020 China Collegiate Programming Contest, Weihai Site) 線段樹
阿新 • • 發佈:2020-11-21
題意
有一個一個長度為n的陣列a和兩種操作(1代表對區間\([l,r]\)加1,2代表詢問區間\([x,x+L-1]\)和區間\([y,y+L-1]\)是否相同),其中操作1對65536取模。
思路
容易想到可以用雜湊判斷是否相等。然後題目中的陣列是對65536取模的,就會想到hash的模數取65536,即用unsigned short
自然溢位取模,但是這個模數被出題人卡掉了。
另外,做字串雜湊時,雜湊的模數一般會選用大指數。因為當base和mod互質時,這個hash函式在\([0,mod)\)上每個值概率相等,此時單次比較的錯誤率為\(\frac1{mod}\)
對於65536取模的情況,與 codeforces438D相同,除了區間和外再加一個區間最大值,對於大於等於65536的區間暴力修改。
程式碼
#include<bits/stdc++.h> using namespace std; typedef long long ll; const ll mod=1e9+7; const ll base=1e8+7; const int maxn=5e5+5; struct Tree{ ll max,sum,tag; }tree[maxn*4]; ll a[maxn],p[maxn],pre[maxn]; int n,q; ll M(ll val){ return val>=mod?val-mod:val<0?val+mod:val; } void push_up(int i) { tree[i].max=max(tree[i<<1].max,tree[i<<1|1].max); tree[i].sum=M(tree[i<<1].sum+tree[i<<1|1].sum); } void push_down(int i,int L,int R) { if(tree[i].tag) { tree[i<<1].max+=tree[i].tag; tree[i<<1|1].max+=tree[i].tag; int mid=L+R>>1; if(L!=mid) tree[i<<1].tag+=tree[i].tag; if(mid+1!=R) tree[i<<1|1].tag+=tree[i].tag; tree[i<<1].sum=M(tree[i<<1].sum+M(pre[mid]-pre[L-1])*tree[i].tag%mod); tree[i<<1|1].sum=M(tree[i<<1|1].sum+M(pre[R]-pre[mid])*tree[i].tag%mod); tree[i].tag=0; } } void build(int i,int l,int r) { if(l==r) { tree[i].max=a[l]; tree[i].sum=a[l]*p[l]%mod; tree[i].tag=0; return; } int mid=l+r>>1; build(i<<1,l,mid); build(i<<1|1,mid+1,r); push_up(i); } void add(int i,int l,int r,int L,int R) { push_down(i,L,R); if(l==L && r==R) { if(l==r) { tree[i].max++; if(tree[i].max==65536)tree[i].max=0; tree[i].sum=tree[i].max*p[l]%mod; return; } else if(tree[i].max<65535) { tree[i].max++; tree[i].tag++; tree[i].sum=M(tree[i].sum+M(pre[R]-pre[L-1])); return; } } int mid=L+R>>1; if(r<=mid) add(i<<1,l,r,L,mid); else if(l>mid) add(i<<1|1,l,r,mid+1,R); else { add(i<<1,l,mid,L,mid); add(i<<1|1,mid+1,r,mid+1,R); } push_up(i); } ll cal(int i,int l,int r,int L,int R) { push_down(i,L,R); int mid=L+R>>1; if(l==L && r==R)return tree[i].sum; if(r<=mid) return cal(i<<1,l,r,L,mid); else if(l>mid) return cal(i<<1|1,l,r,mid+1,R); else return M(cal(i<<1,l,mid,L,mid)+cal(i<<1|1,mid+1,r,mid+1,R)); } int main() { ios::sync_with_stdio(false); cin>>n>>q; for(int i=1;i<=n;i++) cin>>a[i]; p[0]=1; pre[0]=1; for(int i=1;i<=n;i++) { p[i]=p[i-1]*base%mod; pre[i]=M(pre[i-1]+p[i]); } build(1,1,n); int op,l,r,x,y,L; while(q--) { cin>>op; if(op==1) { cin>>l>>r; add(1,l,r,1,n); } else { cin>>x>>y>>L; if(x>y)swap(x,y); ll res1=cal(1,x,x+L-1,1,n),res2=cal(1,y,y+L-1,1,n); if(res1*p[y-x]%mod==res2) cout<<"yes\n"; else cout<<"no\n"; } } return 0; }