BZOJ-3211花神游历各国 并查集+树状数组
2015-12-05 21:56
423 查看
一开始想写线段树区间开方,简单暴力下,但觉得变成复杂度稍高,懒惰了,编了个复杂度简单的
3211: 花神游历各国
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 1706 Solved: 651
[Submit][Status][Discuss]
Description
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
HINT
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
代码如下:
话说这个题后来修改时T了一遍,W了一遍,懵懂中搜索了一下,竟是我DCrusher蛋哥的blog,可惜蛋神做法太高端,于是还是自己修改去了,╮(╯▽╰)╭
3211: 花神游历各国
Time Limit: 5 Sec Memory Limit: 128 MB
Submit: 1706 Solved: 651
[Submit][Status][Discuss]
Description
Input
Output
每次x=1时,每行一个整数,表示这次旅行的开心度
Sample Input
4
1 100 5 5
5
1 1 2
2 1 2
1 1 2
2 2 3
1 1 4
Sample Output
101
11
11
HINT
对于100%的数据, n ≤ 100000,m≤200000 ,data[i]非负且小于10^9
这道题一打眼看就是区间操作,就想到线段树和树状数组,一开始想暴力开根到1为止,写个线段树区间开方 但感觉编程复杂度相对较高,外加时间复杂度不低,于是写了个树状数组+并查集 树状数组的用处不用多说,并查集的用处比较精妙: 用并查集维护一下,维护每个数右边第一个不为1的数字,暴力开根, 如果开根成1后,把他的父亲连到右边数的父亲上,这样在连续修改上,就可以跳过大量连续的1了 666666
代码如下:
#include<iostream> #include<cstdio> #include<algorithm> #include<cstring> #include<cmath> using namespace std; #define maxn 100001 long long love[maxn]={0}; int past[maxn]={0}; int father[maxn]={0}; int n; int lowbit(int x) { return x&(-x); } void change(int loc,int data) { while (loc<=n) { love[loc]+=data; loc+=lowbit(loc); } } long long sum(int loc) { long long tot=0; while (loc>0) { tot+=love[loc]; loc-=lowbit(loc); } return tot; } int find(int x) { if (x==father[x]) return x; else { father[x]=find(father[x]); return father[x]; } } int main() { scanf("%d",&n); for (int i=1; i<=n; i++) { int x; scanf("%d",&x); change(i,x); past[i]=x; if (past[i]<=1) father[i]=i+1; else father[i]=i;//一开始对father的初始化 } int m; father[n+1]=n+1; scanf("%d",&m); for (int i=1; i<=m; i++) { int command,l,r; scanf("%d%d%d",&command,&l,&r); if (command==1) { long long ans=sum(r)-sum(l-1); printf("%lld\n",ans); } else { for (l=find(l); l<=r; l=find(l+1)) { int delta=floor(sqrt(past[l])); change(l,delta-past[l]);//变成开根的方法,就是先减掉自己本身再加上开根,所以可以直接减去自身和开根的差 past[l]=delta; if (past[l]==1) father[l]=find(l+1);//如果开根到1了,就把father连到右边数的father上 } } } return 0; }
话说这个题后来修改时T了一遍,W了一遍,懵懂中搜索了一下,竟是我DCrusher蛋哥的blog,可惜蛋神做法太高端,于是还是自己修改去了,╮(╯▽╰)╭
相关文章推荐
- 数学规律,一元二次方程求最大值。
- 电子或通信领域当前的主流技术及其谁会需求调查报告
- 面向对象六原则
- [简单实用系列] 通用adapter
- ECMAScript 关键字与保留字
- Android Permission 机制
- Spring的MVC相比Structs2有什么优点
- day3
- day4
- ZYB's Biology
- zoj 3349 Special Subsequence 【离散化二分 + 线段树优化dp】
- POJ 2007 Scrambled Polygon (凸包输出点路径)
- 异步调用实现java
- tyvj P1039 线段树点修改和区间查询
- 浏览器处理 前台传递的+时出现问题
- 【Leetcode】Rotate Image
- Android中startActivity中的permission检测与UID机制
- MYSQL的binary解决mysql数据大小写敏感问题
- 如何在RHEL/CentOS 7.0中使用tmpfs
- 黑马程序员-Java的面向对象(抽象类、接口、内部类和继承、组合、多态)