【洛谷P4145】花神遊歷各國
阿新 • • 發佈:2019-03-25
修改 uil fine mes fin sca ons ret def
題目大意:給定一個長度為 N 的序列,支持區間開根,區間求和。
題解:對於區間開根操作,可以發現任何一個位置的值開根至多 6 次就會變成 1。因此即使是整個區間開根,暴力修改6次後,所有的點的權值均小於等於1,即 \(O(6n)\) 時間之後,再修改對序列的值已經不會產生影響,因此忽略後面的開根操作即可,這可以通過維護一個區間最大值來實現。
代碼如下
#include <bits/stdc++.h> using namespace std; const int maxn=1e5+10; int n,m; long long a[maxn]; struct node{ #define ls(x) t[x].lc #define rs(x) t[x].rc int lc,rc; long long sum,mx; }t[maxn<<1]; int tot,root; inline void pushup(int o){ t[o].mx=max(t[ls(o)].mx,t[rs(o)].mx); t[o].sum=t[ls(o)].sum+t[rs(o)].sum; } int build(int l,int r){ int o=++tot; if(l==r)return t[o].sum=t[o].mx=a[l],o; int mid=l+r>>1; ls(o)=build(l,mid),rs(o)=build(mid+1,r); return pushup(o),o; } void modify(int o,int l,int r,int x,int y){ if(l==r){t[o].sum=t[o].mx=sqrt(t[o].sum);return;} int mid=l+r>>1; if(y<=mid){if(t[ls(o)].mx>1)modify(ls(o),l,mid,x,y);} else if(x>mid){if(t[rs(o)].mx>1)modify(rs(o),mid+1,r,x,y);} else{ if(t[ls(o)].mx>1)modify(ls(o),l,mid,x,mid); if(t[rs(o)].mx>1)modify(rs(o),mid+1,r,mid+1,y); } pushup(o); } long long query(int o,int l,int r,int x,int y){ if(l==x&&r==y)return t[o].sum; int mid=l+r>>1; if(y<=mid)return query(ls(o),l,mid,x,y); else if(x>mid)return query(rs(o),mid+1,r,x,y); else return query(ls(o),l,mid,x,mid)+query(rs(o),mid+1,r,mid+1,y); } int main(){ scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%lld",&a[i]); root=build(1,n); scanf("%d",&m); while(m--){ int opt,x,y; scanf("%d%d%d",&opt,&x,&y); if(x>y)swap(x,y); if(opt==0)modify(root,1,n,x,y); else printf("%lld\n",query(root,1,n,x,y)); } return 0; }
【洛谷P4145】花神遊歷各國