hdu 6315 Naive Operations(線段樹 加ok標記)
阿新 • • 發佈:2018-11-10
看大佬部落格:https://www.cnblogs.com/chenquanwei/p/9374234.html
題意:有兩個操作:
1:a陣列l到r的區間都加1;
2:計算l到r內a[i]/b[i]的值的和;
可以只用一個b陣列,每次進行1操作的時候就給相應位置減一,減到零以後就給相應的答案加一(答案就是記錄a[i]/b[i]的值,只有b[i]減到一次零,答案才加一),同時把b陣列的值在置為初始值;
#include <iostream> #include <string> #include <cstring> #include <algorithm> using namespace std; typedef long long ll; const int maxn = 1e5+10; int n,m,x,y; char q[10]; int a[maxn];//記錄初始的b陣列的值 struct node{ int mi,add,sum; } t[maxn<<2]; /* mi是記錄當前的值,也是區間的最小值,當區間的最小值減到0, 就查詢是哪個子節點減到了0,將其答案加一後,mi賦回初始值; add是記錄訪問次數,記錄的是負值,每次更新的時候, 只要add不為0,就把add標記往下推,然後把add置為0; sum記錄答案; */ void build(int l,int r,int rt){ if(l==r){ t[rt].mi = a[l]; t[rt].add=t[rt].sum=0; return; } int mid = (l+r)>>1; build(l,mid,rt<<1); build(mid+1,r,rt<<1|1); t[rt].mi = min(t[rt<<1].mi,t[rt<<1|1].mi); t[rt].sum =t[rt].add = 0; } void pushdown(int l,int r,int rt){//標記往下推 if(!t[rt].add) return;//已經更新過了或者不需要更新,直接返回; t[rt<<1].mi += t[rt].add; t[rt<<1|1].mi += t[rt].add; t[rt<<1].add += t[rt].add; t[rt<<1|1].add += t[rt].add; t[rt].add=0; } //ok表示區間內是否存在答案,即mi等於0;ok為1表示不存在,存在就立即更新節點 void update(int L,int R,int l,int r,int rt,bool ok){//更新 if(L<=l&&r<=R){ if(ok){ t[rt].add--; t[rt].mi--; } if(t[rt].mi) return;//不存在值直接返回 if(l==r){ if(!t[rt].mi) t[rt].sum++,t[rt].mi=a[l]; //有答案,更新mi和sum,add已經在它的標記往下推的時候被置為0了; return;//子節點,不往下推了,返回; } ok = 0; } pushdown(l,r,rt);//標記往下推 int mid = (l+r)>>1; if(L<=mid) update(L,R,l,mid,rt<<1,ok); if(R>mid) update(L,R,mid+1,r,rt<<1|1,ok); t[rt].mi = min(t[rt<<1].mi,t[rt<<1|1].mi); t[rt].sum = t[rt<<1].sum + t[rt<<1|1].sum; } int query(int L,int R,int l,int r,int rt){ if(L<=l&&r<=R) return t[rt].sum; int ans = 0,mid = (l+r)>>1; if(L<=mid) ans += query(L,R,l,mid,rt<<1); if(R>mid) ans+=query(L,R,mid+1,r,rt<<1|1); return ans; } int main() { while(~scanf("%d%d",&n,&m)){ for(int i = 1;i <= n;i++) scanf("%d",&a[i]); build(1,n,1); while(m--){ scanf("%s%d%d",q,&x,&y); if(q[0]=='a') update(x,y,1,n,1,1); else printf("%d\n",query(x,y,1,n,1)); } } return 0; }