poj3468 A Simple Problem with Integers(Splay)

来源:互联网 发布:d3.js 鼠标右键 编辑:程序博客网 时间:2024/06/15 20:04

题目:http://poj.org/problem?id=3468

题意:区间修改,查询区间的和。

分析:线段树+懒惰标记的模版题。。。

现在改用Splay来写。

前面几个题插入的时候用Insert,就是按值的大小来插入的。

现在用元素在数组里面的位置进行插入,就是按位置的大小来插的。

一旦插入完成有序性就固定了。因为rotate操作里面并没有用到值的大小。

所以,中序遍历出来的结果就和原数组对应。

建树和线段树很像。。。

代码:

#include <cstdio>#include <iostream>using namespace std;typedef long long LL;typedef unsigned long long ULL;const LL INF = 1E9+9;const int MI = ~0u>>1;#define lson son[rt][0]#define rson son[rt][1]#define getPos son[son[root][1]][0] const int maxn = 1e5+7;int son[maxn][2],fa[maxn],val[maxn],sz[maxn];LL add[maxn],sum[maxn]; //懒惰标记,和以当前节点为根节点的子树和 int root,cnt;int num[maxn],n,q;inline void pushdown(int rt){if(add[rt]){sum[lson]+=sz[lson]*add[rt];sum[rson]+=sz[rson]*add[rt];add[lson]+=add[rt];add[rson]+=add[rt];val[lson]+=add[rt];val[rson]+=add[rt];add[rt]=0;}}inline void pushup(int rt){sz[rt]=sz[lson]+sz[rson]+1;sum[rt]=sum[lson]+sum[rson]+val[rt];  //左右区间并没有相连!!! }inline int newnode(int f,int v){++cnt;son[cnt][0]=son[cnt][1]=0;fa[cnt]=f;val[cnt]=v;sz[cnt]=1;sum[cnt]=v;add[cnt]=0;return cnt;}void Rotate(int r,int kind){int y=fa[r];pushdown(y);        pushdown(r);son[y][kind^1]=son[r][kind];fa[son[r][kind]] = y;if(fa[y]!=0)son[fa[y]][son[fa[y]][1]==y] = r;fa[r]=fa[y];son[r][kind]=y;fa[y]=r; pushup(y);}void Splay(int r,int goal)  {pushdown(r); while(fa[r]!=goal){if(goal==fa[fa[r]])Rotate(r,son[fa[r]][0]==r);else{int y=fa[r];int kind=son[fa[y]][0]==y;if(son[y][kind]==r){Rotate(r,kind^1);Rotate(r,kind);}else{Rotate(y,kind);Rotate(r,kind);}}}if(0==goal)root=r;pushup(r);}void RotateTo(int k,int goal)  //将代表位置k的节点移到goal下面{int rt=root;while(rt){if(sz[lson]+1==k) break;if(k>sz[lson]+1){k-=(sz[lson]+1);rt=rson;}else rt=lson;}Splay(rt,goal);}void buildSplay(int l,int r,int &rt,int fa){if(l>r) return ;int mid=(l+r)>>1;rt=newnode(fa,num[mid]);buildSplay(l,mid-1,lson,rt);buildSplay(mid+1,r,rson,rt);pushup(rt); }void Init(){cnt=root=0; //设置虚根root=newnode(0,-1);       //在序列首部插入一个元素 son[root][1]=newnode(root,-1);  //在序列尾部插入一个元素 buildSplay(1,n,getPos,son[root][1]); //将序列插在中间 }void Q(int L,int R)  //由于先前首位各添加了一个节点,所以调整的节点的编号要+1 { RotateTo(L,0);  //不算在首部加了一个节点的话就是L-1 RotateTo(R+2,root);  //不算在首部加了一个节点的话就是R+1printf("%I64d\n",sum[getPos]);}void C(int L,int R,int v){RotateTo(L,0);RotateTo(R+2,root);val[getPos]+=v;add[getPos]+=v;sum[getPos]+=1ll*sz[getPos]*v;}int main(){while(scanf("%d%d",&n,&q)!=EOF){for(int i=1;i<=n;i++)scanf("%d",num+i);Init();char op[2];while(q--){int L,R,v;scanf("%s%d%d",op,&L,&R);switch(op[0]){case 'Q':Q(L,R);break;case 'C':scanf("%d",&v);C(L,R,v);}}}return 0;}


0 0