您的位置:首页 > 其它

HDU4267(2012年长春站)

2016-02-27 09:05 169 查看
这道题真的是好题,让我对线段树有了全新的认识,至少让我真正感受到了线段树的神奇。

题意是就是线段树区间更新,单点询问的问题,不过这个题好就好在它的区间更新的点并不连续!

adding c to each of Ai which satisfies a <= i <= b and (i - a) % k == 0.

关键在于更新的点所满足的条件 1.在区间[a,b]中。 2.关于k的余数与(a%k)相等。

其中第二个条件保证了更新的点不连续(但如果传统的先判断再更新,则线段树失去了优势,因为始终会超时)。

本题突破口在于K的大小(1 <= k <= 10),结合第二个条件,我们可以想到在线段树的 Lazy标记上做文章。

当k==1 余数有 0

当k==2 余数有 0,1

当k==3 余数有 0,1,2

。。。。。

可以看到,只有55种情况,那么我们只需要将线段树的 Lazy标记 扩充为大小55的数组,

然后根据相应的余数情况进行更新与查询即可。

#include<iostream>
#include<sstream>
#include<stack>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<climits>
#include<cctype>
#include<queue>
#include<algorithm>
#include<cmath>
#include<map>
#include<set>
#define lson root<<1,l,mid
#define rson root<<1|1,mid+1,r

#define inf 0x3f3f3f3f
#define N 50010
#define maxn 10001000
#define mod 1000000007
using namespace std;

int a
;
int b[11][11];     //用于将55种余数情况一 一 对 应
struct NODE{
int l,r;
int v;
int b[55];
int mid(){
return (l+r)>>1;
}
}node[N<<2];

void build(int root,int l,int r)
{
node[root].l=l;
node[root].r=r;
node[root].v=0;
memset(node[root].b,0,sizeof(node[root].b));
if(l==r) return;
int mid=node[root].mid();
build(lson);
build(rson);
}

void pushdown(int root)   //关于pushdown函数,个人觉得只需要询问时调用就行了,而且也过了,应该没问题,有的话请指出,谢谢
{
for(int i=1; i<=10; ++i)
{
for(int j=0; j<i; ++j)
{
node[root<<1].b[b[i][j]]+=node[root].b[b[i][j]];
node[root<<1|1].b[b[i][j]]+=node[root].b[b[i][j]];
}
}
memset(node[root].b,0,sizeof(node[root].b));
}

void update(int x,int y,int root,int v,int k,int rd)
{
if(node[root].l==x&&node[root].r==y)
{
node[root].b[b[k][rd]]+=v;
node[root].v+=v;
return;
}
int mid=node[root].mid();
if(y<=mid) update(x,y,root<<1,v,k,rd);
else if(x>mid) update(x,y,root<<1|1,v,k,rd);
else
{
update(x,mid,root<<1,v,k,rd);
update(mid+1,y,root<<1|1,v,k,rd);
}
}

int query(int root,int x)
{
if(node[root].l==x&&node[root].r==x)
{
int ans=0;
for(int i=1; i<=10; ++i)
ans+=node[root].b[b[i][x%i]];
return ans;
}
pushdown(root);
int mid=node[root].mid();
if(x<=mid) return query(root<<1,x);
else return query(root<<1|1,x);
}

int main()
{
// freopen("lxx.txt","r",stdin);
int group,figure,i,j,x,y,k,v,num;
int cnt=0;
for(i=1; i<=11; ++i)
for(j=0; j<i; ++j)
b[i][j]=cnt++;
while(~scanf("%d",&group))
{
build(1,1,group);
memset(a,0,sizeof(a));
for(i=1; i<=group; ++i) scanf("%d",&a[i]);
scanf("%d",&group);
while(group--)
{
scanf("%d",&num);
if(num==1)
{
scanf("%d%d%d%d",&x,&y,&k,&v);
update(x,y,1,v,k,x%k);
}
else
{
scanf("%d",&figure);
printf("%d\n",query(1,figure)+a[figure]);
}
}
}
return 0;
}


不过感觉自己的代码风格还不够成熟,继续努力!
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: