bzoj3211 花神游历各国
Description
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
11
11
HINT
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
c++的除法是向下取整,很明显,(a+b)/k!=a/k+b/k(在向下取整的情况下),而根号,很明显根号(a)+根号(b)!=根号(a+b)
第一个想法就是暴力,对于每个要改动的区间l~r,把里面的每个点都单独除,但这样就会把时间复杂度卡得比大暴力都慢(因为多个常数),所以怎么优化?
我们对于每个区间,维护她的最大值和最小值,然后每次修改时,如果这个区间的最大值根号和最小值的根号一样,说明这个区间整体根号不会产生误差,就直接修改(除法同理)
其中,lazytage把除法当成减法,记录的是这个区间里每个元素减去的值。
#include <iostream> #include <cstdio> #include <algorithm> #include <cstring> #include <cmath> #define MAXN 1000010 #define REP(i,k,n) for(int i=k;i<=n;i++) #define in(a) a=read() using namespace std; int read(){ int x=0,f=1; char ch=getchar(); for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1; for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0'; return x*f; } struct node{ int l,r; long long lz,sum,maxx,minn; }tree[MAXN<<2]; int n,m,input[MAXN]; inline void build(int i,int l,int r){ tree[i].l=l;tree[i].r=r; if(l==r){ tree[i].sum=tree[i].minn=tree[i].maxx=input[l]; return ; } int mid=(l+r)>>1; build(i*2,l,mid); build(i*2+1,mid+1,r); tree[i].sum=tree[i*2].sum+tree[i*2+1].sum; tree[i].minn=min(tree[i*2].minn,tree[i*2+1].minn); tree[i].maxx=max(tree[i*2].maxx,tree[i*2+1].maxx); return ; } inline void push_down(int i){ if(!tree[i].lz) return ; long long k=tree[i].lz; tree[i*2].lz+=k; tree[i*2+1].lz+=k; tree[i*2].sum-=(tree[i*2].r-tree[i*2].l+1)*k; tree[i*2+1].sum-=(tree[i*2+1].r-tree[i*2+1].l+1)*k; tree[i*2].minn-=k; tree[i*2+1].minn-=k; tree[i*2].maxx-=k; tree[i*2+1].maxx-=k; tree[i].lz=0; return ; } inline void Sqrt(int i,int l,int r){ if(tree[i].l>=l && tree[i].r<=r && (tree[i].minn-(long long)sqrt(tree[i].minn))==(tree[i].maxx-(long long)sqrt(tree[i].maxx))){ long long u=tree[i].minn-(long long)sqrt(tree[i].minn); tree[i].lz+=u; tree[i].sum-=(tree[i].r-tree[i].l+1)*u; tree[i].minn-=u; tree[i].maxx-=u; //cout<<"i"<<i<<" "<<tree[i].sum<<endl; return ; } if(tree[i].r<l || tree[i].l>r) return ; push_down(i); if(tree[i*2].r>=l) Sqrt(i*2,l,r); if(tree[i*2+1].l<=r) Sqrt(i*2+1,l,r); tree[i].sum=tree[i*2].sum+tree[i*2+1].sum; tree[i].minn=min(tree[i*2].minn,tree[i*2+1].minn); tree[i].maxx=max(tree[i*2].maxx,tree[i*2+1].maxx); //cout<<"i"<<i<<" "<<tree[i].sum<<endl; return ; } inline long long search(int i,int l,int r){ if(tree[i].l>=l && tree[i].r<=r) return tree[i].sum; if(tree[i].r<l || tree[i].l>r) return 0; push_down(i); long long s=0; if(tree[i*2].r>=l) s+=search(i*2,l,r); if(tree[i*2+1].l<=r) s+=search(i*2+1,l,r); return s; } int main(){ in(n); REP(i,1,n) in(input[i]); build(1,1,n); in(m); int a,b,c; REP(i,1,m){ in(a);in(b);in(c); if(a==1) printf("%lld\n",search(1,b,c)); if(a==2){ Sqrt(1,b,c); //for(int i=1;i<=7;i++) // cout<<tree[i].sum<<" "; // cout<<endl; } } }