首页 > 代码库 > HDU 4902 线段树||暴力
HDU 4902 线段树||暴力
给定一个序列,两种操作
1:把一段变成x。
2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列。
线段树解法:用lazy标记下即可,优化方法还是很巧妙的,
Accepted | 4902 | 515MS | 3308K | 1941 B | C++ |
#include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作。 }data[400010]; int gcd(int a,int b) { if(b==0) return a;else return gcd(b,a%b); } void build(int l,int r,int k) { int mid; data[k].l=l; data[k].r=r; data[k].x=-1; if (l==r) { scanf("%d",&data[k].x); return ; } mid=(l+r)/2; build(l,mid,k*2); build(mid+1,r,k*2+1); } void cover(int l,int r,int k,int x) { int mid; if (data[k].l==l && data[k].r==r) { data[k].x=x; return ; } mid=(data[k].l+data[k].r)/2; if (data[k].x!=-1) // lazy 操作 { cover(data[k].l,mid,k*2,data[k].x); cover(mid+1,data[k].r,k*2+1,data[k].x); data[k].x=-1; } if (r<=mid) cover(l,r,k*2,x); else if (l>mid) cover(l,r,k*2+1,x); else { cover(l,mid,k*2,x); cover(mid+1,r,k*2+1,x); } } void updata(int l,int r,int k,int x) { int mid; if (data[k].x!=-1) // 操作2的优化 { if (data[k].x<=x) return ; // 如果下面的成端更新值小于x,则不进行操作2 cover(l,r,k,gcd(data[k].x,x)); // 否则把成端更新的进行操作2再更新 return ; } mid=(data[k].l+data[k].r)/2; if (r<=mid) updata(l,r,k*2,x); else if (l>mid) updata(l,r,k*2+1,x); else { updata(l,mid,k*2,x); updata(mid+1,r,k*2+1,x); } } void pri(int k) { int i; if (data[k].x!=-1) { for (i=data[k].l;i<=data[k].r;i++) printf("%d ",data[k].x); return ; } pri(k*2); pri(k*2+1); } int main() { int Case,op,a,b,x,n,m; scanf("%d",&Case); while (Case--) { scanf("%d",&n); build(1,n,1); scanf("%d",&m); while (m--) { scanf("%d%d%d%d",&op,&a,&b,&x); if(op==1) cover(a,b,1,x); else updata(a,b,1,x); } pri(1); printf("\n"); } return 0; }
其实这题也可以暴力水过,,,,竟然比线段树快,对每一个节点,按操作方式从后往前更新,如果遇到操作1就停止,否则记录操作2,再对当前点正向计算一遍即可。
Accepted | 4902 | 250MS | 3336K | 754 B | C |
#include "stdio.h" #include "string.h" struct node { int l,r,op; __int64 x; }mark[100010]; __int64 a[101000],pri,b[101000]; __int64 gcd(__int64 a,__int64 b) { if(b==0)return a; return gcd(b,a%b); } int main() { int Case,n,i,j,sum,m; scanf("%d",&Case); while (Case--) { scanf("%d",&n); for (i=1;i<=n;i++) scanf("%I64d",&a[i]); scanf("%d",&m); for (i=1;i<=m;i++) scanf("%d%d%d%I64d",&mark[i].op,&mark[i].l,&mark[i].r,&mark[i].x); for (i=1;i<=n;i++) // 对于每个点按操作从后往前更新 { pri=a[i]; sum=0; for (j=m;j>=1;j--) if (mark[j].l<=i && mark[j].r>=i) { if (mark[j].op==1) //遇到操作1就停止 { pri=mark[j].x; break; } else { b[sum++]=mark[j].x; //记录中间遇到的操作2 } } if (sum==0) printf("%I64d ",pri); else { for (j=sum-1;j>=0;j--) if (pri>b[j]) pri=gcd(pri,b[j]); printf("%I64d ",pri); } } printf("\n"); } return 0; }
声明:以上内容来自用户投稿及互联网公开渠道收集整理发布,本网站不拥有所有权,未作人工编辑处理,也不承担相关法律责任,若内容有误或涉及侵权可进行投诉: 投诉/举报 工作人员会在5个工作日内联系你,一经查实,本站将立刻删除涉嫌侵权内容。