【codevs4919】線段樹練習4
阿新 • • 發佈:2018-11-25
題目大意:維護一個長度為 N 的序列,支援兩種操作:區間加,區間查詢有多少數是 7 的倍數。
題解:在每個線段樹中維護一個權值陣列 [0,6],由於個數顯然支援區間可加性,因此可用線段樹來維護。
程式碼如下
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; inline int read(){ int x=0,f=1;char ch; do{ch=getchar();if(ch=='-')f=-1;}while(!isdigit(ch)); do{x=x*10+ch-'0';ch=getchar();}while(isdigit(ch)); return f*x; } int n,q,a[maxn],tmp[7];//處理迴圈需要額外開一個數組 char opt[10]; struct node{int lc,rc,tag,cnt[7];}; struct segment_tree{ #define ls t[k].lc #define rs t[k].rc node t[maxn<<1]; int tot; segment_tree():tot(1){ memset(t,0,sizeof(t)); } inline void pushup(int k){ for(int i=0;i<7;i++)t[k].cnt[i]=t[ls].cnt[i]+t[rs].cnt[i]; } inline void cycle(int k,int val){ for(int i=0;i<7;i++)tmp[i]=t[k].cnt[i]; for(int i=0;i<7;i++)t[k].cnt[(i+val)%7]=tmp[i]; } inline void pushdown(int k){ cycle(ls,t[k].tag),cycle(rs,t[k].tag); t[ls].tag=(t[ls].tag+t[k].tag)%7; t[rs].tag=(t[rs].tag+t[k].tag)%7; t[k].tag=0; } void build(int k,int l,int r){ if(l==r){t[k].cnt[a[l]%7]++;return;} int mid=l+r>>1; ls=++tot,build(ls,l,mid); rs=++tot,build(rs,mid+1,r); pushup(k); } void modify(int k,int l,int r,int x,int y,int val){ if(l==x&&r==y){ cycle(k,val); t[k].tag=(t[k].tag+val)%7; return; } int mid=l+r>>1; pushdown(k); if(y<=mid)modify(ls,l,mid,x,y,val); else if(x>mid)modify(rs,mid+1,r,x,y,val); else modify(ls,l,mid,x,mid,val),modify(rs,mid+1,r,mid+1,y,val); pushup(k); } int query(int k,int l,int r,int x,int y){ if(l==x&&r==y)return t[k].cnt[0]; int mid=l+r>>1; pushdown(k); if(y<=mid)return query(ls,l,mid,x,y); else if(x>mid)return query(rs,mid+1,r,x,y); else return query(ls,l,mid,x,mid)+query(rs,mid+1,r,mid+1,y); } }sgt; void read_and_parse(){ n=read(); for(int i=1;i<=n;i++)a[i]=read(); sgt.build(1,1,n); q=read(); } void solve(){ int l,r,val; while(q--){ scanf("%s",opt); if(opt[0]=='c'){ l=read(),r=read(); printf("%d\n",sgt.query(1,1,n,l,r)); }else{ l=read(),r=read(),val=read(); sgt.modify(1,1,n,l,r,val); } } } int main(){ read_and_parse(); solve(); return 0; }