HDU 4288 Coder(線段樹+離線處理)
阿新 • • 發佈:2019-01-23
維護一個序列an,有以下三種操作:
一、在序列中新增元素x
二、在序列中刪除元素x
三、計算序列中下標i%5=3的元素和
在寫解題報告之前先廢話幾句關於線段樹的姿勢問題:
之前一直習慣於結構體姿勢的線段樹,後來看了notonlysuccess的線段樹總結,開始採用陣列的方式寫線段樹,結構體的缺點在於浪費了2n的空間(維護區間l和r值),而陣列的缺點在於浪費了常數的時間(傳參),之前在清華校賽中有遇到這種情況,卡常數最後那題一直沒過,這道題也是這種情況,結構體1s多,陣列需要2s多(這題可過,但花費時間太多)。雖然陣列的方式很優雅,但是在必要的時候還是需要考慮一下空間和時間。。。
典型的線段樹單點更新區間查詢問題。
線段樹不支援新增和刪除操作,所以肯定無法線上處理,採用離線的方法。
先預處理資料,將所有資料儲存到a陣列中,並複製到x陣列,將x陣列的所有元素排序去重,然後根據x陣列建立線段樹。
線段樹中維護兩個:num和sum[5]
num表示區間內的元素個數,sum[i]表示區間中所有滿足下標x%5=i的元素和(下標是指區間內的第一個,不是整體)
這樣的話,向上更新的時候滿足
node[rt].sum[i]=node[rt<<1].sum[i]+node[rt<<1|1].sum[((i-node[rt<<1].num)%5+5)%5];
因為右結點的第x元素下標在父結點中應該對應的是第(x+左結點的元素個數)個元素,即i=x+cnt,x=i-cnt,取模是為了防止負數
每次查詢時只需要返回node[1].sum[2]即可
#include<iostream> #include<cstdio> #include<cmath> #include<cstring> #include<cstdlib> #include<cstring> #include<string> #include<queue> #include<algorithm> #include<vector> #include<map> using namespace std; #define lson rt<<1,l,mid #define rson rt<<1|1,mid+1,r typedef __int64 ll; const int INF=0x3f3f3f3f; const int maxn=1e5+10; int n; int a[maxn],x[maxn]; char cmd[maxn][10]; struct Node{ ll sum[5]; int num; }node[maxn<<2]; void PushUp(int rt){ for(int i=0;i<5;i++){ node[rt].sum[i]=node[rt<<1].sum[i]+node[rt<<1|1].sum[((i-node[rt<<1].num)%5+5)%5]; } } void build(int rt,int l,int r){ if(l==r){ memset(node[rt].sum,0,sizeof(node[rt].sum)); node[rt].num=0; return ; } int mid=(l+r)>>1; build(lson); build(rson); memset(node[rt].sum,0,sizeof(node[rt].sum)); node[rt].num=0; } void Update(int rt,int l,int r,int pos,int val,int op){ op?++node[rt].num:--node[rt].num; if(l==r){ node[rt].sum[0]=op*val; return ; } int mid=(l+r)>>1; if(pos<=mid) Update(lson,pos,val,op); else Update(rson,pos,val,op); PushUp(rt); } int main(){ while(~scanf("%d",&n)){ int len=0; for(int i=0;i<n;i++){ scanf("%s",cmd[i]); if(cmd[i][0]!='s'){ scanf("%d",&a[i]); x[len++]=a[i]; } } sort(x,x+len); len=unique(x,x+len)-x; build(1,1,len); for(int i=0;i<n;i++){ if(cmd[i][0]=='a'){ int k=(int)(lower_bound(x,x+len,a[i])-x)+1; Update(1,1,len,k,a[i],1); } else if(cmd[i][0]=='d'){ int k=(int)(lower_bound(x,x+len,a[i])-x)+1; Update(1,1,len,k,a[i],0); } else{ printf("%I64d\n",node[1].sum[2]); } } } return 0; }