HDU-4267:A Simple Problem with Integers(多线段树选择更新)

来源:互联网 发布:北京网络 编辑:程序博客网 时间:2024/05/16 23:34


题目链接:点击打开链接

题意解析:

题意很容易理解就不多讲了。


解题思路:

这道题刚开始想了好久,真不知道怎么做。。。后来看网上博客,大致分为树状数组和线段树两种做法。因为树状数组内存小,代码短,就先学习了树状数组的写法。刚开始看了一篇奇怪的博客,坑了好久,博主用了一种很神奇的方法,看了好长时间看不懂,后来看了些其他博客,终于大致明白了树状数组的写法原理。。。然后又去看了线段树,写之前觉得线段树好难写,后来发现线段树其实比树状数组容易理解的多。先讲树状数组的写法,

题目最主要的部分就是在a,b区间内下标为 i 的数,如果(i-a)%k==0,那么就更新 i 所在的位置的数的值。解题的关键就是化简为 i%k==a%k。要深刻的理解这一点,

从而建立树状数组 d[i][k][mod], mod=a%k, 以此更新,然后树状数组储存的就是每个点的变化值,最后查询的时候输出这个点+它的变化值即可。不过个人认为树状数组还是难以理解,还是线段树好懂,以下先贴树状数组的代码,

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <queue>#include <map>#include <algorithm>#include <set>#include <functional>using namespace std;typedef long long LL;typedef unsigned long long ULL;int n,m;int a[50005];int d[50005][11][11];int sum(int a){    int i=a,s=0;    while(i>0)    {        for(int j=1;j<=10;j++)            s += d[i][j][a%j];        i -= i&-i;    }    return s;}void add(int l,int k,int mod,int c){    int i=l;    while(i<=n)    {        d[i][k][mod] += c;        i += i&-i;    }}int main(){    while(scanf("%d",&n)!=EOF)    {        memset(d,0,sizeof(d));        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        scanf("%d",&m);        int p,l,r,k,c;        for(int i=0;i<m;i++)        {            scanf("%d",&p);            if(p==1)            {                scanf("%d%d%d%d",&l,&r,&k,&c);                add(l,k,l%k,c);                add(r+1,k,l%k,-c);            }            if(p==2)            {                scanf("%d",&l);                printf("%d\n",a[l]+sum(l));            }        }    }}



线段树:

线段树的做法相比于树状数组就很容易理解了。

对于 k从1到10,对每个k取余,一共有55种情况,例如1取余1种情况,2取余两种,依次类推,最后能得到55种情况。

那么我们可以根据这55种情况维护55棵线段树,每次更新的时候,选择对应情况的线段树进行更新,听起来55棵线段树真tm吓人,其实还好。就是每个节点里面存了个大小55的数组,大家千万不要被吓到,我刚开始就是被吓到了,所以没写线段树,去搞了什么树状数组,真有点难懂。55棵线段树更新的时候选择对应的更新,然后查询的时候将所有符合要求的线段树的值加上即可,以下贴线段树的代码,

#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cstdlib>#include <cmath>#include <vector>#include <queue>#include <map>#include <algorithm>#include <set>#include <functional>#define lson rt<<1#define rson rt<<1|1using namespace std;typedef long long LL;typedef unsigned long long ULL;int n,m,ans;int a[50005],cc[11];struct tree         //sum55就是传说中的55棵线段树{    int l,r,mid;    int sum[55];    int mark;}t[200010];void pushdown(int rt)      //自上向下维护 注意传给下面节点后要清0{    if(t[rt].mark==-1)    {        for(int i=0;i<55;i++)        {            t[lson].sum[i]+=t[rt].sum[i];            t[rson].sum[i]+=t[rt].sum[i];            t[rt].sum[i]=0;        }        t[rt].mark=0;        t[lson].mark=t[rson].mark=-1;    }}void build(int l,int r,int rt)   //建树过程中初始化 memset貌似会t 队友说的{    int mid=(l+r)>>1;    for(int i=0;i<55;i++)        t[rt].sum[i]=0;    t[rt].l=l;t[rt].r=r;    t[rt].mid=mid;    t[rt].mark=0;    if(l==r)        return ;    build(l,mid,lson);    build(mid+1,r,rson);}void update(int l,int r,int k,int c,int rt){    if(t[rt].l>=l&&t[rt].r<=r)    {        int co=cc[k-1]+l%k;     //选择合适的线段树进行更新        t[rt].sum[co]=t[rt].sum[co]+c;        t[rt].mark=-1;        return ;    }    pushdown(rt);    if(l<=t[rt].mid)        update(l,r,k,c,lson);    if(r>t[rt].mid)        update(l,r,k,c,rson);}int query(int q,int rt){    if(t[rt].l==t[rt].r&&q==t[rt].l)    {        int s=0;        for(int i=1;i<=10;i++)      //将所有符合要求的线段树值加入            s += t[rt].sum[cc[i-1]+q%i];        return s;    }    pushdown(rt);    if(q<=t[rt].mid)        return query(q,lson);    else        return query(q,rson);}int main(){    cc[0]=0;    for(int i=1;i<=10;i++)      //帮助我们得到每种情况对应到0到54的值        cc[i]=cc[i-1]+i;    while(scanf("%d",&n)!=EOF)    {        build(1,n,1);        for(int i=1;i<=n;i++)            scanf("%d",&a[i]);        scanf("%d",&m);        int p,l,r,k,c;        for(int i=0;i<m;i++)        {            scanf("%d",&p);            if(p==1)            {                scanf("%d%d%d%d",&l,&r,&k,&c);                update(l,r,k,c,1);            }            if(p==2)            {                scanf("%d",&l);                ans=a[l]+query(l,1);                printf("%d\n",ans);            }        }    }}





阅读全文
0 0