線段樹對區間取模。node
考試前就想寫的題目QAQ,cxlove點了一下以後知道是什麼回事了,先說下作法,暴力更新就好了,維護區間的最大值,每次把要取模的區間的最大值取出來,暴力更新,因爲取模的性質能夠保證每次取模以後至少比原數的一半還少,因此總體複雜度仍是比較低的。ui
如今簡單證實下a%b < a / 2:spa
首先咱們先設b = ka , k屬於(0,1]blog
1.若k <= 0.5 , 則根據%的運算符很容易獲得a % b < 0.5a.input
2.若k > 0.5,直接用減法能夠替代取模運算,a -= b,容易得出a = (1 - k)a < 0.5a;string
證畢。it
貼代碼:io
#include <cstdio> #include <cstring> #include <algorithm> #define LL long long #define lson l,m,rt << 1 #define rson m + 1,r,rt << 1 | 1 #define lc rt << 1 #define rc rt << 1 | 1 using namespace std; const int N = 100050; int n,q; struct Node { LL sum,maxVal; int from; }node[N << 2]; inline void pushUp(int rt){ node[rt].sum = node[lc].sum + node[rc].sum; if(node[lc].maxVal < node[rc].maxVal){ node[rt].maxVal = node[rc].maxVal; node[rt].from = node[rc].from; } else{ node[rt].maxVal = node[lc].maxVal; node[rt].from = node[lc].from; } } inline void build(int l,int r,int rt){ if(l == r){ scanf("%I64d",&node[rt].sum); node[rt].maxVal = node[rt].sum; node[rt].from = l; return ; } int m = (l + r) >> 1; build(lson); build(rson); pushUp(rt); } inline void assign(int p,int val,int l,int r,int rt){ // printf("val:%d\n",val); if(l == r){ node[rt].sum = node[rt].maxVal = val; return ; } int m = (l + r) >> 1; if(p <= m) assign(p,val,lson); else assign(p,val,rson); pushUp(rt); } inline pair<int,int> queryMax(int L,int R,int l,int r,int rt){ if(L <= l && r <= R) return make_pair(node[rt].maxVal,node[rt].from); int m = (l + r) >> 1; pair<int,int> ret = make_pair(-1,1); if(L <= m) ret = queryMax(L,R,lson); if(R > m) ret = max(ret,queryMax(L,R,rson)); return ret; } inline LL query(int L,int R,int l,int r,int rt){ if(L <= l && r <= R){ return node[rt].sum; } int m = (l + r) >> 1; LL ret = 0; if(L <= m) ret += query(L,R,lson); if(R > m) ret += query(L,R,rson); return ret; } int main(){ // freopen("input.txt","r",stdin); // freopen("output.txt","w",stdout); scanf("%d%d",&n,&q); build(1,n,1); while(q --){ int op;scanf("%d",&op); if(op == 1){ int l,r;scanf("%d%d",&l,&r); printf("%I64d\n",query(l,r,1,n,1)); } else if (op == 2){ int l,r,x;scanf("%d%d%d",&l,&r,&x); while(true){ pair<int,int> ret = queryMax(l,r,1,n,1); // printf("l:%d r:%d max:%d from:%d new:%d\n",l,r,ret.first,ret.second,ret.first%x); if(ret.first >= x){ assign(ret.second,ret.first % x,1,n,1); } else break; } } else{ int k,x;scanf("%d%d",&k,&x); assign(k,x,1,n,1); } } return 0; }