概述
题目链接:点击打开链接
题目大意:
给你一些数让你依次添加到一个集合中,集合中的数是递增的。并且中间会求集合中下标mod5=3的数的和
解题思路:
自己完全不会做,表示线段树怎么能用来写这种东西。
后来还是给大神跪了。据说可以暴力压时间水过,不过也没尝试。
具体的思路就是先将所有数离线保存起来,然后依次再加入线段树中,具体操作也说不太清楚。
中间有一步左加右减的操作。很神奇。先将代码搬过来 t[rt].sum[i]=t[lson].sum[i]+t[rson].sum[(i-t[lson].cnt%5+5)%5]; cnt表示当前节点有效数字
可以看到当前节点 mod5=i 的值是由左节点 mod5=i 的值+右节点 mod5=x(暂且用x表示)。x=(i-t[lson].cnt%5+5)%5
这部分可能有些难以理解,举个例子说明吧 假设现在左节点有4个有效数字 ,右节点有4个有效数字。 那么他们在集合中的下标理论上是 1到8.
假设现在求 mod5=3 的值。那么左儿子就要取 下标mod5=3 的那些数,左儿子下标是正常从1开始的。但是右儿子的有效数字虽然集合中的下标是从5到8,但是在它的线段树中实际上还是1到4,那么我们当前节点mod5=3的数应该有两个 下标为3和下标为8。但是右儿子现在下标不是从5开始,所以就需要转化一下即 x=(i-t[lson].cnt%5+5)%5
下面贴代码
#include <iostream>
#include <cstdio>
#include <cstring>
#include <cstdlib>
#include <cmath>
#include <vector>
#include <queue>
#include <map>
#include <algorithm>
#include <set>
#include <functional>
#define rank ra
#define lson rt<<1
#define rson rt<<1|1
#define pb push_back
using namespace std;
typedef long long ll;
int n,m,ans;
int a[100010],v[100010];
char c[100010][5];
struct node
{
int l,r,mid;
int cnt;
//记录有效数字的个数
ll sum[5];
//分别mod5=i的和
}t[500000];
void pushup(int rt)
{
t[rt].cnt=t[lson].cnt+t[rson].cnt;
//更新有效数字
for(int i=0;i<5;i++)
//更新当前值得和
t[rt].sum[i]=t[lson].sum[i]+t[rson].sum[(i-t[lson].cnt%5+5)%5];
}
void build(int l,int r,int rt)
//初始化
{
int mid=(l+r)>>1;
t[rt].l=l;t[rt].r=r;
t[rt].mid=mid;
for(int i=0;i<5;i++)
t[rt].sum[i]=0;
t[rt].cnt=0;
if(l==r)
return ;
build(l,mid,lson);
build(mid+1,r,rson);
}
void update(int idx,int flag,int rt)
{
if(t[rt].l==t[rt].r)
{
if(flag)
//更新操作
{
t[rt].sum[1]=v[idx];
t[rt].cnt=1;
}
if(flag<0)
{
t[rt].sum[1]=0;
t[rt].cnt=0;
}
return ;
}
if(idx<=t[rt].mid)
update(idx,flag,lson);
if(idx>t[rt].mid)
update(idx,flag,rson);
pushup(rt);
}
int main()
{
while(scanf("%d",&n)!=EOF)
{
int p=0;
for(int i=1;i<=n;i++)
{
scanf(" %s",c[i]);
if(c[i][0]!='s')
{
scanf("%d",&a[i]);
v[++p]=a[i];
//离线储存
}
}
int k=1;
sort(v+1,v+1+p);
//排序去重
for(int i=2;i<=p;i++)
{
if(v[i]!=v[i-1])
v[++k]=v[i];
}
build(1,k,1);
for(int i=1;i<=n;i++)
{
if(c[i][0]=='s')
cout<<t[1].sum[3]<<endl;
int idx=lower_bound(v+1,v+1+k,a[i])-v;
//找到大于等于它的最小的数所在位置
if(c[i][0]=='a')
update(idx,1,1);
if(c[i][0]=='d')
update(idx,-1,1);
}
}
}
最后
以上就是喜悦牛排为你收集整理的HDU-4288:Coder(线段树+离线操作)的全部内容,希望文章能够帮你解决HDU-4288:Coder(线段树+离线操作)所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
本图文内容来源于网友提供,作为学习参考使用,或来自网络收集整理,版权属于原作者所有。
发表评论 取消回复