1. 程式人生 > >POJ 3468 A Simple Problem with Integers (Splay 區間更新、區間求和)

POJ 3468 A Simple Problem with Integers (Splay 區間更新、區間求和)

題目連結

題目大意

線段樹區間更新的模板題,用Splay寫一遍作為用Splay處理區間問題的模板題。

分析

程式碼

#include <iostream>
#include <cstdio>
#include <cstring>
#include <cmath>
#include <algorithm>
#include <queue>
#include <string>
#define ls (rt<<1)
#define rs (rt<<1|1)
#define bit(x) (1<<(x))
using namespace std; typedef long long LL; const double pi=4*atan(1.0); const int INF=0x3f3f3f3f; const double eps=1e-6; const int MAXN=100010; const int MAXM=2*MAXN; int a[MAXN],n; struct SplayTree { #define Key_value (nt[nt[root][1]][0]) int root,tot; int nt[MAXN][2],pre[MAXN],val[MAXN],Size[MAXN],add[MAXN]; LL sum[MAXN]; void
Newnode(int &rt,int fa,int v) { rt=++tot; nt[rt][0]=nt[rt][1]=0; pre[rt]=fa; val[rt]=v; add[rt]=sum[rt]=0; Size[rt]=1; } void Update_Add(int rt,int v) { if (rt==0) return; val[rt]+=v; add[rt]+=v; sum[rt]+=(LL) v*Size[rt]; } void
PushUp(int rt) { Size[rt]=1+Size[nt[rt][0]]+Size[nt[rt][1]]; sum[rt]=sum[nt[rt][0]]+sum[nt[rt][1]]+val[rt]; } void PushDown(int rt) { if (add[rt]) { Update_Add(nt[rt][0],add[rt]); Update_Add(nt[rt][1],add[rt]); add[rt]=0; } } void Build(int &rt,int l,int r,int fa)///建立一棵完全平衡的二叉樹,中序遍歷即為原序列 { if (l>r) return; int mid=(l+r)>>1; Newnode(rt,fa,a[mid]); Build(nt[rt][0],l,mid-1,rt); Build(nt[rt][1],mid+1,r,rt); PushUp(rt); } void Init() { for (int i=1;i<=n;i++) scanf("%d",&a[i]); root=tot=0; nt[root][0]=nt[root][1]=pre[root]=Size[root]=val[root]=sum[root]=add[root]=0; Newnode(root,0,-1); Newnode(nt[root][1],root,-1);///為了能夠正常提取區間,需要在序列的首位各新增一個-1 Build(Key_value,1,n,nt[root][1]); PushUp(nt[root][1]); PushUp(root); } void Rotate(int x,int kind)///旋轉:kind 0為左旋,1為右旋 { int y=pre[x]; PushDown(y); PushDown(x); nt[y][!kind]=nt[x][kind]; pre[nt[x][kind]]=y; if(pre[y]) nt[pre[y]][nt[pre[y]][1]==y]=x; pre[x]=pre[y]; nt[x][kind]=y; pre[y]=x; PushUp(y); } void Splay(int x,int goal)///Splay調整:將結點x調整到goal下面 { PushDown(x); while(pre[x]!=goal) { if(pre[pre[x]]==goal) ///單旋情況 Rotate(x,nt[pre[x]][0]==x); else { int y=pre[x]; int kind= nt[pre[y]][0]==y; if(nt[y][kind]==x) ///之字形旋轉 { Rotate(x,!kind); Rotate(x,kind); } else ///一字形旋轉 { Rotate(y,kind); Rotate(x,kind); } } } PushUp(x); if(goal==0) root=x; } int Get_Kth(int rt,int k)///尋找序列中第k個數 { PushDown(rt); int t=Size[nt[rt][0]]+1; if (k==t) return rt;///如果rt就是第k個數 else if (k<t) return Get_Kth(nt[rt][0],k); else return Get_Kth(nt[rt][1],k-t); } void Add(int l,int r,int v) { Splay(Get_Kth(root,l),0); Splay(Get_Kth(root,r+2),root); Update_Add(Key_value,v); PushUp(nt[root][1]); PushUp(root); } LL Query(int l,int r) { Splay(Get_Kth(root,l),0); Splay(Get_Kth(root,r+2),root); return sum[Key_value]; } }st; int main() { char op[10]; int Q,x,y,z; while (scanf("%d%d",&n,&Q)!=EOF) { st.Init(); while (Q--) { scanf("%s",op); if (op[0]=='C') { scanf("%d%d%d",&x,&y,&z); st.Add(x,y,z); } if (op[0]=='Q') { scanf("%d%d",&x,&y); printf("%lld\n",st.Query(x,y)); } } } return 0; }