hdu-4348-To the moon-离线处理 or 主席树区间更新
2016-08-24 19:59
429 查看
题意:
-------------------------------------------------------------------------------------------------------------------------
第一种解法,按离线建树,写起来比较简单:
类似 http://blog.csdn.net/viphong/article/details/52264179
也就是根据询问之间的先后顺序建立树,然后dfs一遍,在过程中求解。注意建立的是询问之间的关系,而不时间的关系
处理询问只需要用到一个线段树区间更新即可
-------------------------------------------------------------------------------------------------------------------------
第二种解法
用主席树实现线段树的区间更新和查询,并支持历史版本信息的访问。
此处为了避免MLE,把区间更新的lazy标记去掉,改成维护sum和fix两个信息的单点更新实现区间更新,思想类似于前缀和
就是对于add(l,r,val)的操作变成
add_sum_fix(l,val)
{
sum[i]+=val;
fix[i]+=(l-1)*val;
}
add_sum_fix(r+1,val)
那么我们查询【l,r】只需要查询
ll query(int t,int x)
{
if (x<1) return 0;
ll sum=querysum(t,1,n,1,x);
ll ff=queryfix(t,1,n,1,x);
return sum*x-ff;
}
离线按询问建树的代码:
主席树区间更新代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const int MAXNN=100005;
typedef long long ll;
#define w(i) T[(i)].w
#define fix(i) T[(i)].fix
#define ls(i) T[(i)].ls
#define rs(i) T[(i)].rs
int n,m;
struct node
{
int ls,rs;
ll w,fix;
} T[MAXNN*51];
ll aa[100005];
int root[MAXNN+50],sz;
int build_tree(int l,int r)
{
int t=++sz;
T[t].w=T[t].fix=0;
if (l==r) return t;
int mid=(l+r)>>1;
T[t].ls=build_tree(l,mid);
T[t].rs=build_tree(mid+1,r);
return t;
}
int update(int i,int x,int val,int l,int r)
{
T[++sz]=T[i];
i=sz;
if (l==r)
{
T[i].w+=val;
T[i].fix+=1LL*(x-1)*val;
return i;
}
int m=(l+r)>>1;
if (x<=m) ls(i)=update(ls(i),x,val,l,m);
else rs(i)=update(rs(i),x,val,m+1,r);
T[i].w=w(ls(i))+w(rs(i));
T[i].fix=fix(ls(i))+fix(rs(i));
return i;
}
ll queryfix(int i,int l,int r,int ql,int qr )
{
if (ql>r||qr<l) return 0;
if (ql<=l&&qr>=r) return T[i].fix;
int m=(l+r)>>1;
return queryfix(ls(i) ,l,m,ql,qr)
+ queryfix(rs(i),m+1,r,ql,qr);
}
ll querysum(int i ,int l,int r,int ql,int qr)
{
if (ql>r||qr<l) return 0;
if (ql<=l&&qr>=r) return T[i].w;
int m=(l+r)>>1;
return querysum(ls(i) ,l,m,ql,qr)
+ querysum(rs(i),m+1,r,ql,qr);
}
void init()
{
root[0]=0;
sz=0;
}
ll query(int t,int x)
{
if (x<1) return 0;
ll sum=querysum(t,1,n,1,x);
ll ff=queryfix(t,1,n,1,x);
return sum*x-ff;
}
int main()
{
//DO YOLO
while(scanf("%d%d",&n,&m)!=EOF)
{
for (int i=1; i<=n; i++)
scanf("%lld",&aa[i]),aa[i]+=aa[i-1];
init();
int time=0;
root[time]=build_tree(1,n);
char op[5];
int x,y,z;
for (int i=1; i<=m; i++)
{
scanf("%s",op);
if (op[0]=='C')
{
scanf("%d%d%d",&x,&y,&z);
root[time+1]=update(root[time],x,z,1,n);
root[time+2]=update(root[time+1],y+1,-z,1,n);
time+=2;
}
else if (op[0]=='Q')
{
scanf("%d%d",&x,&y);
ll RR=query(root[time],y);
ll LL=query(root[time],x-1);
ll ans=RR-LL+aa[y]-aa[x-1];
printf("%lld\n",ans);
}
else if (op[0]=='H')
{
scanf("%d%d%d",&x,&y,&z);
ll RR=query(root[2*z],y);
ll LL=query(root[2*z],x-1);
ll ans=RR-LL+aa[y]-aa[x-1];
printf("%lld\n",ans);
}
else
{
int z;
scanf("%d",&z);
time=z*2;
sz=root[time+1]; //?????k
}
}
}
return 0;
}
-------------------------------------------------------------------------------------------------------------------------
第一种解法,按离线建树,写起来比较简单:
类似 http://blog.csdn.net/viphong/article/details/52264179
也就是根据询问之间的先后顺序建立树,然后dfs一遍,在过程中求解。注意建立的是询问之间的关系,而不时间的关系
处理询问只需要用到一个线段树区间更新即可
-------------------------------------------------------------------------------------------------------------------------
第二种解法
用主席树实现线段树的区间更新和查询,并支持历史版本信息的访问。
此处为了避免MLE,把区间更新的lazy标记去掉,改成维护sum和fix两个信息的单点更新实现区间更新,思想类似于前缀和
就是对于add(l,r,val)的操作变成
add_sum_fix(l,val)
{
sum[i]+=val;
fix[i]+=(l-1)*val;
}
add_sum_fix(r+1,val)
那么我们查询【l,r】只需要查询
ll query(int t,int x)
{
if (x<1) return 0;
ll sum=querysum(t,1,n,1,x);
ll ff=queryfix(t,1,n,1,x);
return sum*x-ff;
}
离线按询问建树的代码:
#include <cstdio> #include <cmath> #include <cstring> #include <string> #include <algorithm> #include <queue> #include <map> #include <bitset> #include <vector> #include <iostream> using namespace std; const double pi=acos(-1.0); double eps=0.000001; typedef long long ll; const int N = 100005 ; ll ans[100005]; struct TREE { ll sum[4*N], add[4*N] ; void pushDown(int i, int l, int r) //把i节点的延迟标记传递到左右儿子节点 { if(add[i] != 0) { int mid = (l + r) >> 1; add[i << 1] += add[i]; sum[i << 1] += (mid - l + 1) * add[i]; //[l, mid]代表左儿子区间 add[i << 1 | 1] += add[i]; sum[i << 1 | 1] += (r - mid) * add[i]; //[mid + 1, r]代表右儿子区间 add[i] = 0; } } void update(int i, int l, int r, int ql, int qr, ll val) //更新区间为qlqr,当前区间为l,r,代表当前区间和的节点为i,更新值为val, { if(l > qr || ql > r) //更新区间不在当前区间内 return ; if(l >= ql && r <= qr) //要更新的区间把当前区间完全包括,则把当前整个区间+val,然后返回上一层 { sum[i] +=1LL* (r - l + 1) * val; add[i] += val; return ; } pushDown(i, l, r); //如果上面没reutrn 表示要往左右儿子区间查询,所以把延迟标记放下去 int mid = (l + r) >> 1; update(i << 1, l, mid, ql, qr, val); update(i << 1 | 1, mid + 1, r, ql, qr, val); sum[i] = sum[i << 1] + sum[i << 1 | 1]; } ll query(int i, int l, int r, int ql, int qr) //查询区间为qlqr,当前区间为l,r,代表当前区间和的节点为i { if(l > qr || ql > r) return 0; if(l >= ql && r <= qr) return sum[i]; pushDown(i, l, r); //同update int mid =( l + r) >> 1; return query(i << 1, l, mid, ql, qr) + query(i << 1 | 1, mid + 1, r, ql, qr); } void init() { memset(sum,0,sizeof sum); memset(add,0,sizeof add); } } tp; struct node { int x,y,z; char kind; }; vector<int >mp[100050]; node tt[100050]; int n, q; void deal(int x) { char k=tt[x].kind; int i=tt[x].x; int j=tt[x].y; int z=tt[x].z; if (k=='C') tp.update(1,1,n,i,j,z); if (k=='Q') ans[x]=tp.query(1,1,n,i,j); if (k=='H') ans[x]=tp.query(1,1,n,i,j); } void redeal(int x) { char k=tt[x].kind; int i=tt[x].x; int j=tt[x].y; int z=tt[x].z; tp.update(1,1,n,i,j,-z); } bool cmp(int a,int b) { return tt[a].kind>tt[b].kind; } void dfs(int x) { if (x) deal(x); sort(mp[x].begin(),mp[x].end(),cmp); for (int i=0; i<mp[x].size(); i++) { int v=mp[x][i]; dfs(v); } if (x&&tt[x].kind=='C') redeal(x); } int time_event[100005]; int main() { int x; while(scanf("%d%d",&n,&q)!=EOF) { tp.init(); for (int i=1; i<=n; i++)scanf("%d",&x),tp.update(1,1,n,i,i,x); for (int i=0; i<=q; i++) mp[i].clear(); char op[5]; int time=0; for (int i=1; i<=q; i++) { scanf("%s",op); tt[i].kind=op[0]; if (op[0]=='C') { scanf("%d%d%d",&tt[i].x,&tt[i].y,&tt[i].z); mp[time_event[time]].push_back(i); time++; time_event[time]=i; } else if (op[0]=='H') { scanf("%d%d%d",&tt[i].x,&tt[i].y,&tt[i].z); mp[time_event[tt[i].z]].push_back(i); } else if (op[0]=='B') { scanf("%d",&tt[i].x); mp[time_event[tt[i].x]].push_back(i); time=tt[i].x; } else { scanf("%d%d",&tt[i].x,&tt[i].y); mp[ time_event[time]].push_back(i); } } dfs(0); for (int i=1; i<=q; i++) if (tt[i].kind=='Q'||tt[i].kind=='H') printf("%lld\n",ans[i]); } return 0; }
主席树区间更新代码:
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <algorithm>
#include <queue>
#include <map>
#include <set>
#include <vector>
#include <iostream>
using namespace std;
const int MAXNN=100005;
typedef long long ll;
#define w(i) T[(i)].w
#define fix(i) T[(i)].fix
#define ls(i) T[(i)].ls
#define rs(i) T[(i)].rs
int n,m;
struct node
{
int ls,rs;
ll w,fix;
} T[MAXNN*51];
ll aa[100005];
int root[MAXNN+50],sz;
int build_tree(int l,int r)
{
int t=++sz;
T[t].w=T[t].fix=0;
if (l==r) return t;
int mid=(l+r)>>1;
T[t].ls=build_tree(l,mid);
T[t].rs=build_tree(mid+1,r);
return t;
}
int update(int i,int x,int val,int l,int r)
{
T[++sz]=T[i];
i=sz;
if (l==r)
{
T[i].w+=val;
T[i].fix+=1LL*(x-1)*val;
return i;
}
int m=(l+r)>>1;
if (x<=m) ls(i)=update(ls(i),x,val,l,m);
else rs(i)=update(rs(i),x,val,m+1,r);
T[i].w=w(ls(i))+w(rs(i));
T[i].fix=fix(ls(i))+fix(rs(i));
return i;
}
ll queryfix(int i,int l,int r,int ql,int qr )
{
if (ql>r||qr<l) return 0;
if (ql<=l&&qr>=r) return T[i].fix;
int m=(l+r)>>1;
return queryfix(ls(i) ,l,m,ql,qr)
+ queryfix(rs(i),m+1,r,ql,qr);
}
ll querysum(int i ,int l,int r,int ql,int qr)
{
if (ql>r||qr<l) return 0;
if (ql<=l&&qr>=r) return T[i].w;
int m=(l+r)>>1;
return querysum(ls(i) ,l,m,ql,qr)
+ querysum(rs(i),m+1,r,ql,qr);
}
void init()
{
root[0]=0;
sz=0;
}
ll query(int t,int x)
{
if (x<1) return 0;
ll sum=querysum(t,1,n,1,x);
ll ff=queryfix(t,1,n,1,x);
return sum*x-ff;
}
int main()
{
//DO YOLO
while(scanf("%d%d",&n,&m)!=EOF)
{
for (int i=1; i<=n; i++)
scanf("%lld",&aa[i]),aa[i]+=aa[i-1];
init();
int time=0;
root[time]=build_tree(1,n);
char op[5];
int x,y,z;
for (int i=1; i<=m; i++)
{
scanf("%s",op);
if (op[0]=='C')
{
scanf("%d%d%d",&x,&y,&z);
root[time+1]=update(root[time],x,z,1,n);
root[time+2]=update(root[time+1],y+1,-z,1,n);
time+=2;
}
else if (op[0]=='Q')
{
scanf("%d%d",&x,&y);
ll RR=query(root[time],y);
ll LL=query(root[time],x-1);
ll ans=RR-LL+aa[y]-aa[x-1];
printf("%lld\n",ans);
}
else if (op[0]=='H')
{
scanf("%d%d%d",&x,&y,&z);
ll RR=query(root[2*z],y);
ll LL=query(root[2*z],x-1);
ll ans=RR-LL+aa[y]-aa[x-1];
printf("%lld\n",ans);
}
else
{
int z;
scanf("%d",&z);
time=z*2;
sz=root[time+1]; //?????k
}
}
}
return 0;
}
相关文章推荐
- hdu-4348-To the moon-主席树在线区间更新
- hdu-4348-To the moon(主席树更新,区间更新,区间和查询,保存历史版本返回)
- hdu 4348 To the moon (主席树区间更新)
- hdu 4348 To the moon(主席树,区间更新节省内存,经典)
- hdu 4348 To the moon 主席树区间更新
- 【HDU - 4348】To the moon(主席树在线区间更新)
- HDU 4348 To the moon 主席树 + 区间更新
- HDU 4348 To the moon(主席树区间更新)
- HDU 4348 To the moon (主席树区间更新)
- HDU 4348 To the moon [主席树 区间修改]
- hdu 4348 To the moon(主席树区间操作)
- HDU 4348 To the moon(主席树区间修改)
- HDU 4348 To the moon 【主席树+区间修改】
- HDU 4348 To the moon 可持久化线段树,有时间戳的区间更新,区间求和
- SPOJ TTM - To the moon (主席树,区间更新,区间查询)
- hdu 4348 To the moon (主席树)
- hdu4348 - To the moon 可持久化线段树 区间修改 离线处理
- HDU-4348 To the moon(主席树)
- hdu-4348:To the moon(主席树+懒惰标记)
- HDU - 4348 To the moon (可持久化线段树,区间查询加累加)