438D - The Child and Sequence
#include <stdio.h> #include <algorithm> using namespace std; #define lson num << 1 #define rson num << 1 | 1 #define MAXN 100005 typedef long long ll; int a[MAXN << 1]; struct node { int l,r; ll Max,sum; }tree[MAXN << 2]; void pushup(ll rt){ tree[rt].Max = max(tree[rt << 1].Max,tree[rt << 1|1].Max); tree[rt].sum = tree[rt << 1].sum + tree[rt << 1|1].sum; } // void build(int num,int l,int r) // { // tree[num].l = l; // tree[num].r = r; // if(l == r) { // //scanf("%I64d",&tree[num].Max); // tree[num].sum = tree[num].Max = a[l]; // return; // } // int mid = (l + r) >> 1; // build(lson,l,mid); // build(rson,mid + 1,r); // pushup(num); // } void build(ll rt,ll l ,ll r){ tree[rt].l = l , tree[rt].r = r; if(l == r){ tree[rt].sum = tree[rt].Max = a[l]; return; } ll mid = (l + r) >> 1; build(rt << 1, l , mid); build(rt <<1|1,mid + 1,r); pushup(rt); } // ll query(int num,int l,int r) // { // if(tree[num].l == l && tree[num].r == r) { // return tree[num].sum; // } // int mid = (tree[num].l + tree[num].r) >> 1; // if(r <= mid) { // return query(lson,l,r); // } // else if(l > mid) { // return query(rson,l,r); // } // else { // return query(lson,l,mid) + query(rson,mid + 1,r); // } // } ll query(ll rt,ll l,ll r){ if(tree[rt].l == l && r == tree[rt].r){ return tree[rt].sum; }//cout << rt << endl; ll mid = (tree[rt].l + tree[rt].r) >> 1; if(r <= mid) return query(rt << 1,l ,r); else if(l > mid) return query(rt << 1|1,l,r); else return query(rt << 1,l, mid) + query(rt << 1|1 , mid + 1, r); } // void update1(int num,int l,int r,int mod) // { // if(tree[num].Max < mod) { // return; // } // if(tree[num].l == tree[num].r) { // tree[num].Max %= mod; // tree[num].sum %= mod; // return; // } // int mid = (tree[num].l + tree[num].r) >> 1; // if(r <= mid) { // update1(lson,l,r,mod); // } // else if(l > mid) { // update1(rson,l,r,mod); // } // else { // update1(lson,l,mid,mod),update1(rson,mid + 1,r,mod); // } // pushup(num); // } void update1(ll rt,ll l ,ll r ,ll v){ // cout << t[rt].maxx << endl; if(v > tree[rt].Max) return; if( tree[rt].l == tree[rt].r){ tree[rt].Max %= v; tree[rt].sum %= v; // cout << t[rt].sum << " " << 111 << endl; return; } // ll mid = (tree[rt].l + tree[rt].r) >> 1; if(r <= mid) update1(rt << 1,l ,r,v); else if(l > mid) update1(rt << 1|1,l,r,v); else update1(rt << 1,l, mid,v) , update1(rt << 1|1 , mid + 1, r,v); pushup(rt); } // void update2(int num,int pos,int val) // { // if(tree[num].l == tree[num].r && tree[num].l == pos) { // tree[num].sum = val; // tree[num].Max = val; // return; // } // int mid = (tree[num].l + tree[num].r) >> 1; // if(pos <= mid) { // update2(lson,pos,val); // } // else { // update2(rson,pos,val); // } // pushup(num); // } void update2(ll rt,ll x,ll v){ if(tree[rt].l == tree[rt].r && tree[rt].l == x){ tree[rt].Max = tree[rt].sum = v; return; } ll mid = (tree[rt].l + tree[rt].r) >> 1; if(x <= mid) update2(rt << 1,x , v); else update2(rt << 1|1,x , v); pushup(rt); } // int main(void) // { // int n,m; // scanf("%d%d",&n,&m); // for(int i = 1; i <= n; i++) scanf("%d",&a[i]); // build(1,1,n); // while(m--) { // int op,l,r,pos,x; // scanf("%d",&op); // if(op == 1) { // scanf("%d%d",&l,&r); // printf("%I64d\n",query(1,l,r)); // } // else if(op == 2) { // scanf("%d%d%d",&l,&r,&x); // update1(1,l,r,x); // } // else { // scanf("%d%d",&pos,&x); // update2(1,pos,x); // } // } // return 0; // } int main(int argc, char const *argv[]) { ll n , m ; scanf("%lld%lld",&n,&m); for(ll i = 1;i <= n ; i++) scanf("%lld",&a[i]); build(1,1,n); //for(ll i = 1;i <= 40; i++) cout << t[i].sum << endl; while(m--){ ll a; scanf("%lld",&a); if(a == 1){ ll b , c; scanf("%lld%lld",&b,&c); printf("%lld\n",query(1,b,c)); }else if(a == 2){ ll b ,c, pos; scanf("%lld%lld%lld",&b,&c,&pos); update1(1,b,c,pos); }else{ ll b , c; scanf("%lld%lld",&b,&c); update2(1,b,c); } } return 0; }
线段树重要思想
线段树单点修改的本质就是区间修改
本题是对所有数取模,如果对区间和取模,必定会影响子节点,那么便只能对子节点取模
但是如果一个一个取模,便会有超时的危险
那么我们就可以利用剪枝的思想,对小于mod的数/区间,直接返回
只对大于mod的数进行取模,那么便能降低复杂度。
#include <stdio.h> #include <algorithm> using namespace std; #define lson num << 1 #define rson num << 1 | 1 #define MAXN 100005 typedef long long ll; struct node { int l,r; ll Max,sum; }tree[MAXN << 2]; void pushup(int num) { tree[num].Max = max(tree[lson].Max,tree[rson].Max); tree[num].sum = tree[lson].sum + tree[rson].sum; } void build(int num,int l,int r) { tree[num].l = l; tree[num].r = r; if(l == r) { scanf("%I64d",&tree[num].Max); tree[num].sum = tree[num].Max; return; } int mid = (l + r) >> 1; build(lson,l,mid); build(rson,mid + 1,r); pushup(num); } ll query(int num,int l,int r) { if(tree[num].l >= l && tree[num].r <= r) { return tree[num].sum; } int mid = (tree[num].l + tree[num].r) >> 1; if(r <= mid) { return query(lson,l,r); } else if(l > mid) { return query(rson,l,r); } else { return query(lson,l,mid) + query(rson,mid + 1,r); } } void update1(int num,int l,int r,int mod) { if(tree[num].Max < mod) { return; } //因为修改的是最大值,不是区间修改,所以是这个 if(tree[num].l == tree[num].r) { tree[num].Max %= mod; tree[num].sum %= mod; return; } int mid = (tree[num].l + tree[num].r) >> 1; if(r <= mid) { update1(lson,l,r,mod); } else if(l > mid) { update1(rson,l,r,mod); } else { update1(lson,l,mid,mod),update1(rson,mid + 1,r,mod); } pushup(num); } void update2(int num,int pos,int val) { if(tree[num].l == tree[num].r ) { tree[num].sum = val; tree[num].Max = val; return; } int mid = (tree[num].l + tree[num].r) >> 1; if(pos <= mid) { update2(lson,pos,val); } else { update2(rson,pos,val); } pushup(num); } int main(void) { int n,m; scanf("%d%d",&n,&m); build(1,1,n); while(m--) { int op,l,r,pos,x; scanf("%d",&op); if(op == 1) { scanf("%d%d",&l,&r); printf("%I64d\n",query(1,l,r)); } else if(op == 2) { scanf("%d%d%d",&l,&r,&x); update1(1,l,r,x); } else { scanf("%d%d",&pos,&x); update2(1,pos,x); } } return 0; }