POJ 3468 A Simple Problem with Integers (Splay 區間更新、區間求和)
阿新 • • 發佈:2019-01-10
題目連結
題目大意
線段樹區間更新的模板題,用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;
}