zoukankan      html  css  js  c++  java
  • 【codevs4919】线段树练习4

    题目大意:维护一个长度为 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
    ",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;
    }
    
  • 相关阅读:
    acm 总结之大数加法
    hdu 1004
    hdu 1887
    hdu 2007
    hdu 2004
    ACM总结之 A+B problem 总结
    nyoj_42_一笔画问题_201403181935
    最短路径--Floyd算法
    最短路径—Dijkstra算法
    nyoj_114_某种序列_201403161700
  • 原文地址:https://www.cnblogs.com/wzj-xhjbk/p/10016552.html
Copyright © 2011-2022 走看看