POJ-3468 A Simple Problem with Integers Splay Tree区间练习

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

  以前用线段树做过,现在用Splay Tree A了,向HHkuangbincxlove大牛学习了各种Splay各种操作,,,Orz。。

  Splay Tree的区间操作和线段树的操作差不多,也是保存子树的值,然后懒惰操作,在Rotate()最后维护节点信息的时候,只要Push_Up(y)的,因为x还需要网上旋转到根节点,最后更新下就可以了,并且在下一次Rotate()的时候,还会Push_Down(x)的信息,因此不能Push_Up(x)。

  1 //STATUS:C++_AC_3407MS_3696KB

  2 #include <functional>

  3 #include <algorithm>

  4 #include <iostream>

  5 //#include <ext/rope>

  6 #include <fstream>

  7 #include <sstream>

  8 #include <iomanip>

  9 #include <numeric>

 10 #include <cstring>

 11 #include <cassert>

 12 #include <cstdio>

 13 #include <string>

 14 #include <vector>

 15 #include <bitset>

 16 #include <queue>

 17 #include <stack>

 18 #include <cmath>

 19 #include <ctime>

 20 #include <list>

 21 #include <set>

 22 #include <map>

 23 using namespace std;

 24 //using namespace __gnu_cxx;

 25 //define

 26 #define pii pair<int,int>

 27 #define mem(a,b) memset(a,b,sizeof(a))

 28 #define lson l,mid,rt<<1

 29 #define rson mid+1,r,rt<<1|1

 30 #define PI acos(-1.0)

 31 //typedef

 32 typedef __int64 LL;

 33 typedef unsigned __int64 ULL;

 34 //const

 35 const int N=100010;

 36 const int INF=0x3f3f3f3f;

 37 const int MOD=100000,STA=8000010;

 38 const LL LNF=1LL<<60;

 39 const double EPS=1e-8;

 40 const double OO=1e15;

 41 const int dx[4]={-1,0,1,0};

 42 const int dy[4]={0,1,0,-1};

 43 const int day[13]={0,31,28,31,30,31,30,31,31,30,31,30,31};

 44 //Daily Use ...

 45 inline int sign(double x){return (x>EPS)-(x<-EPS);}

 46 template<class T> T gcd(T a,T b){return b?gcd(b,a%b):a;}

 47 template<class T> T lcm(T a,T b){return a/gcd(a,b)*b;}

 48 template<class T> inline T lcm(T a,T b,T d){return a/d*b;}

 49 template<class T> inline T Min(T a,T b){return a<b?a:b;}

 50 template<class T> inline T Max(T a,T b){return a>b?a:b;}

 51 template<class T> inline T Min(T a,T b,T c){return min(min(a, b),c);}

 52 template<class T> inline T Max(T a,T b,T c){return max(max(a, b),c);}

 53 template<class T> inline T Min(T a,T b,T c,T d){return min(min(a, b),min(c,d));}

 54 template<class T> inline T Max(T a,T b,T c,T d){return max(max(a, b),max(c,d));}

 55 //End

 56 

 57 #define Key_value ch[ch[root][1]][0]

 58 int pre[N],key[N],ch[N][2];  //分别表示父结点,键值,左右孩子(0为左孩子,1为右孩子),根结点,结点数量

 59 int sz[N],st[N];   //子树规模,内存池

 60 int root,tot,top;   //根节点,根节点数量,内存池容量

 61 //题目特定数据

 62 int num[N];

 63 int val[N];

 64 int add[N];

 65 LL sum[N];

 66 int n,m;

 67 //debug部分copy from hh

 68 void Treaval(int x) {

 69     if(x) {

 70         Treaval(ch[x][0]);

 71         printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d size = %2d ,val = %2d , sum = %2d \n",x,ch[x][0],ch[x][1],pre[x],sz[x],val[x],sum[x]);

 72         Treaval(ch[x][1]);

 73     }

 74 }

 75 void debug() {printf("%d\n",root);Treaval(root);}

 76 //以上Debug

 77 //新建一个结点

 78 void NewNode(int &x,int fa,int k)

 79 {

 80     if(top)x=st[--top];

 81     else x=++tot;

 82     pre[x]=fa;

 83     sz[x]=1;

 84     val[x]=k;

 85     add[x]=0;

 86     sum[x]=k;

 87     ch[x][0]=ch[x][1]=0;  //左右孩子为空

 88 }

 89 

 90 void Push_Up(int x)

 91 {

 92     sz[x]=sz[ch[x][0]]+sz[ch[x][1]]+1;

 93     sum[x]=sum[ch[x][0]]+sum[ch[x][1]]+val[x];

 94 }

 95 

 96 void Push_Down(int x)

 97 {

 98     if(add[x]){

 99         val[x]+=add[x];

100         add[ch[x][0]]+=add[x];

101         add[ch[x][1]]+=add[x];

102         sum[ch[x][0]]+=(LL)add[x]*sz[ch[x][0]];

103         sum[ch[x][1]]+=(LL)add[x]*sz[ch[x][1]];

104         add[x]=0;

105     }

106 }

107 

108 //旋转,kind为1为右旋,kind为0为左旋

109 void Rotate(int x,int kind)

110 {

111     int y=pre[x],z=pre[y];

112     Push_Down(y);

113     Push_Down(x);  //先把y的标记向下传递,再把x的标记往下传递

114     //类似SBT,要把其中一个分支先给父节点

115     ch[y][!kind]=ch[x][kind];

116     pre[ch[x][kind]]=y;

117     //如果父节点不是根结点,则要和父节点的父节点连接起来

118     if(z)ch[z][ch[z][1]==y]=x;

119     pre[x]=z;

120     ch[x][kind]=y;

121     pre[y]=x;

122     Push_Up(y);  //维护y结点,不要维护x节点,x节点会再次Push_Down,最后维护一下x节点即可

123 }

124 //Splay调整,将根为r的子树调整为goal

125 void Splay(int x,int goal)

126 {

127     int y,kind;

128     while(pre[x]!=goal){

129         //父节点即是目标位置,goal为0表示,父节点就是根结点

130         y=pre[x];

131         if(pre[y]==goal){

132             Rotate(x,ch[y][0]==x);

133         }

134         else {

135             kind=ch[pre[y]][0]==y;

136             //两个方向不同,则先左旋再右旋

137             if(ch[y][kind]==x){

138                 Rotate(x,!kind);

139                 Rotate(x,kind);

140             }

141             //两个方向相同,相同方向连续两次

142             else {

143                 Rotate(y,kind);

144                 Rotate(x,kind);

145             }

146         }

147     }

148     //更新根结点

149     Push_Up(x);

150     if(goal==0)root=x;

151 }

152 

153 void RotateTo(int k,int goal)

154 {

155     int x=root;

156     Push_Down(x);

157     while(sz[ch[x][0]]!=k){

158         if(sz[ch[x][0]]>k)

159             x=ch[x][0];

160         else {

161             k-=sz[ch[x][0]]+1;

162             x=ch[x][1];

163         }

164         Push_Down(x);

165     }

166     Splay(x,goal);

167 }

168 

169 int Insert(int k)

170 {

171     int x=root;

172     while(ch[x][k>key[x]]){

173         //不重复插入

174         if(key[x]==k){

175             Splay(x,0);

176             return 0;

177         }

178         x=ch[x][k>key[x]];

179     }

180     NewNode(ch[x][k>key[x]],x,k);

181     //将新插入的结点更新至根结点

182     Splay(ch[x][k>key[x]],0);

183     return 1;

184 }

185 //找前驱,即左子树的最右结点

186 int Get_Pre(int x)

187 {

188     if(!ch[x][0])return -INF;

189     x=ch[x][0];

190     while(ch[x][1])x=ch[x][1];

191     return key[x];

192 }

193 //找后继,即右子树的最左结点

194 int Get_Suf(int x)

195 {

196     if(!ch[x][1])return INF;

197     x=ch[x][1];

198     while(ch[x][0])x=ch[x][0];

199     return key[x];

200 }

201 //建树,中间结点先建立,然后分别对区间两端在左右子树建立  

202 void BuildTree(int &x,int l,int r,int fa)

203 {

204     if(l>r)return;

205     int mid=(l+r)>>1;

206     NewNode(x,fa,num[mid]);

207     BuildTree(ch[x][0],l,mid-1,x);

208     BuildTree(ch[x][1],mid+1,r,x);

209     Push_Up(x);

210 }

211 

212 void Init()

213 {

214     ch[0][0]=ch[0][1]=pre[0]=sz[0]=0;

215     add[0]=sum[0]=0;

216     root=top=tot=0;

217     NewNode(root,0,-1); 

218     NewNode(ch[root][1],root,-1);     //头尾各加入一个空位

219     sz[root]=2;

220 

221     for(int i=0;i<n;i++)

222         scanf("%d",&num[i]);

223     BuildTree(Key_value,0,n-1,ch[root][1]);    //让所有数据夹在两个-1之间  

224     Push_Up(ch[root][1]);

225     Push_Up(root);

226 }

227 

228 void Update(int a,int b,int c)

229 {

230     RotateTo(a-1,0);

231     RotateTo(b+1,root);

232     add[Key_value]+=c;

233     sum[Key_value]+=sz[Key_value]*c;

234 }

235 

236 LL Query(int a,int b)

237 {

238     RotateTo(a-1,0);

239     RotateTo(b+1,root);

240     return sum[Key_value];

241 }

242 

243 int main()

244 {

245  //   freopen("in.txt","r",stdin);

246     int i,j,a,b,c;

247     char op[2];

248     while(~scanf("%d%d",&n,&m))

249     {

250         Init();

251         while(m--){

252             scanf("%s",op);

253             if(op[0]=='Q'){

254                 scanf("%d%d",&a,&b);

255                 printf("%I64d\n",Query(a,b));

256             }

257             else {

258                 scanf("%d%d%d",&a,&b,&c);

259                 Update(a,b,c);

260             }

261         }

262     }

263     return 0;

264 }

 

你可能感兴趣的:(Integer)