您的位置:首页 > 其它

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 <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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: