HDU 5634 Rikka with Phi(线段树)
2016-02-25 13:58
429 查看
题目链接:点击打开链接
题意:有3种区间操作, 1是把区间内的所有数变成它的欧拉函数值, 2是把区间所有数都变成一个数x,3是查询区间和。
思路:后两个操作就是线段树的区间修改和求和, 没什么好说的。
题解说用平衡树(弱不会), 不过大致思路线段树同样可以维护, 因为一个数进行最多phiO(logn)次就会变成1, 所以我们可以在递归结束,向上传标记的时候顺便看看其子区间是不是都等于1, 是就合并起来, 给这个点重新标记。
细节参见代码:
题意:有3种区间操作, 1是把区间内的所有数变成它的欧拉函数值, 2是把区间所有数都变成一个数x,3是查询区间和。
思路:后两个操作就是线段树的区间修改和求和, 没什么好说的。
题解说用平衡树(弱不会), 不过大致思路线段树同样可以维护, 因为一个数进行最多phiO(logn)次就会变成1, 所以我们可以在递归结束,向上传标记的时候顺便看看其子区间是不是都等于1, 是就合并起来, 给这个点重新标记。
细节参见代码:
#include<cstdio> #include<cstring> #include<algorithm> #include<iostream> #include<string> #include<vector> #include<stack> #include<bitset> #include<cstdlib> #include<cmath> #include<set> #include<list> #include<deque> #include<map> #include<queue> using namespace std; typedef long long ll; typedef long double ld; const ld EPS = 1e-9, PI = 3.1415926535897932384626433832795; const int mod = 1000000000 + 7; const int INF = int(1e9); const ll INF64 = ll(1e18); const int maxn = 300000 + 10; int T, n, m, v, id, l, r, x; ll sum[maxn<<2], setv[maxn<<2]; #define Max 10000010 ll euler[Max] = {0}; void Init(){ euler[1]=1; for(ll i=2;i<Max;i++) euler[i]=i; for(ll i=2;i<Max;i++) if(euler[i]==i) for(ll j=i;j<Max;j+=i) euler[j]=euler[j]/i*(i-1); } void PushUp(int o) { sum[o] = sum[o<<1] + sum[o<<1|1]; if(setv[o<<1] == setv[o<<1|1]) setv[o] = setv[o<<1]; else setv[o] = 0; } void build(int l, int r, int o) { int m = (l + r) >> 1; sum[o] = 0; setv[o] = 0; if(l == r) { scanf("%d",&v); sum[o] = setv[o] = v; return ; } build(l, m, o<<1); build(m+1, r, o<<1|1); PushUp(o); } void pushdown(int l, int r, int o) { if(setv[o]) { int m = (l + r) >> 1; setv[o<<1] = setv[o<<1|1] = setv[o]; sum[o<<1] = (ll)(m - l + 1) * setv[o]; sum[o<<1|1] = (ll)(r - m) * setv[o]; setv[o] = 0; } } void update(int L, int R, int v, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { setv[o] = (ll)v; sum[o] = (ll)v * (r - l + 1); return ; } pushdown(l, r, o); if(L <= m) update(L, R, v, l, m, o<<1); if(m < R) update(L, R, v, m+1, r, o<<1|1); PushUp(o); } void haha(int L, int R, int l, int r, int o) { int m = (l + r) >> 1; if(setv[o] && L <= l && r <= R) { setv[o] = euler[setv[o]]; sum[o] = setv[o] * (r - l + 1); return ; } if(l == r) return ; pushdown(l, r, o); if(L <= m) haha(L, R, l, m, o<<1); if(m < R) haha(L, R, m+1, r, o<<1|1); PushUp(o); } ll query(int L, int R, int l, int r, int o) { int m = (l + r) >> 1; if(L <= l && r <= R) { return sum[o]; } pushdown(l, r, o); ll ans = 0; if(L <= m) ans += query(L, R, l, m, o<<1); if(m < R) ans += query(L, R, m+1, r, o<<1|1); PushUp(o); return ans; } int main() { Init(); scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); build(1, n, 1); while(m--) { scanf("%d%d%d",&id,&l,&r); if(id == 1) haha(l, r, 1, n, 1); else if(id == 2) { scanf("%d",&x); update(l, r, x, 1, n, 1); } else printf("%I64d\n",query(l, r, 1, n, 1)); } } return 0; }
相关文章推荐
- 【bzoj2597】[Wc2007]剪刀石头布 费用流
- SmartDrv的前世今生——PrimoCache_2.2.0汉化
- Unity 偏振3D左右格式画面制作
- 左右滑动切换Activity_绑定SIM_BroadcastReceiver监听手机重启
- Unity 实现倒计时 协程
- 收集好用的在线富文本编辑器
- 2016年回顾过去
- Excel四舍六入五单双公式
- Docker镜像
- Intent详解 (一) : 显式Intent
- POJ 1033
- 安卓开发 弹出对话框,然后自动消失
- redis 入门
- PSYoungGen /PSOldGen/PSPermGen区别
- Cookie与Session的区别
- hdu1085 多重部分和问题
- x264源码分析与应用示例(一)——视频编码基本流程
- 百万级访问量网站的技术准备工作
- register(cp:http://blog.sina.com.cn/s/blog_6a1837e90101128k.html)
- 哈理工OJ 2284 Sign Deliveries(结构体排序)