HDU - 4348To the moon
【題目描述】
【題目分析】
題目中說明每次更新后時間都會加1,而且還會需要查詢以前的區間,還會需要返回以前的時間,所以是很裸的主席樹。區間查詢的話我們同樣需要用到lazy標記
通過這道題我發現線段樹的操作還是很靈活的
借鑒大佬的代碼
【AC代碼】
#include<cstdio>
#include<cstring>
#include<algorithm>using namespace std;typedef long long ll;const int MAXN=100005;
int n,m,Time;
ll a[MAXN];
struct node
{int ls,rs;ll sum,add;
}tree[MAXN*40];
int root[MAXN*40];
int tot;
void build(int &o,int l,int r)
{o=++tot;tree[o].add=0;if(l==r){tree[o].sum=a[l];return;}int mid=(l+r)>>1;build(tree[o].ls,l,mid);build(tree[o].rs,mid+1,r);tree[o].sum=tree[tree[o].ls].sum+tree[tree[o].rs].sum;
}void interval_add(int &x,int l,int r,int L,int R,ll z)
{tree[++tot]=tree[x]; x=tot;tree[x].sum+=z*(R-L+1); //相當于pushupif(l==L && r==R){tree[x].add+=z;return;}int mid=(l+r)>>1;if(R<=mid) interval_add(tree[x].ls,l,mid,L,R,z);//這里通過判斷讓L,R屬于l..mid,方便上面的pushupelse if(L>mid) interval_add(tree[x].rs,mid+1,r,L,R,z);else{interval_add(tree[x].ls,l,mid,L,mid,z);interval_add(tree[x].rs,mid+1,r,mid+1,R,z);}
}ll query(int o,int l,int r,int L,int R)
{if(l>=L && r<=R){return tree[o].sum;}ll ret=tree[o].add*(R-L+1); //pushdown,這里的pushdown沒有將標記下傳,而是將lazy標記保留,詢問的時候依次將路徑上的lazy標記加起來int mid=(l+r)>>1;if(R<=mid) ret+=query(tree[o].ls,l,mid,L,R);else if(L>mid) ret+=query(tree[o].rs,mid+1,r,L,R);else{ret+=query(tree[o].ls,l,mid,L,mid);ret+=query(tree[o].rs,mid+1,r,mid+1,R);}return ret;
}int main()
{char cmd[5];int l,r,t;ll d;while(~scanf("%d%d",&n,&m)){for(int i=1;i<=n;i++){scanf("%lld",&a[i]);}tot=0; Time=0;build(root[0],1,n);for(int i=0;i<m;i++){scanf("%s",cmd);if(cmd[0]=='C'){scanf("%d%d%lld",&l,&r,&d);Time++;root[Time]=root[Time-1];interval_add(root[Time],1,n,l,r,d);}else if(cmd[0]=='Q'){scanf("%d%d",&l,&r);printf("%lld\n",query(root[Time],1,n,l,r));}else if(cmd[0]=='H'){scanf("%d%d%d",&l,&r,&t);printf("%lld\n",query(root[t],1,n,l,r));}else if(cmd[0]=='B'){scanf("%d",&t);Time=t;}}}return 0;
}