ZOJ 5332 Calculation(离线 + 线段树)

题目链接 :http://acm.zju.edu.cn/onlinejudge/showProblem.do?problemId=5332

比赛的时候没有做出来,赛后看了官方题解,虽然各种orz但是依旧只能orz(标程写得真是犀利),然后可耻的到网上找了下题解。。。

做法是线段树 + 离线搞, 网上那种对于[l, r]中的l从大到小排序很精妙(有一篇竟然说是以r为关键字,,,然后代码里面却是l。。。汗), 再注意到gcd()对于每一个起点来说,是单调递减的,这样可以乱搞了...

如果还不是很明白,搜下其他的blog吧,他们写得很丰富。。

贴贴代码,,可耻滚粗。

ps .... zoj为何有时能过有时候又被卡了。。。

  1 #include <cstdio>
  2 #include <cstring>
  3 #include <algorithm>
  4 #include <vector>
  5 //#include <cmath>
  6
  7 using namespace std;
  8 #define lson rt<<1, l, mid
  9 #define rson rt<<1|1, mid+1, r
 10 typedef pair<int, int> PII;
 11 //typedef __int64 lld;
 12 typedef long long lld;
 13 const int MAXN = 100005;
 14
 15 struct Q {
 16     int l, r, id;
 17     Q() {}
 18     Q(int a, int b, int c):l(a), r(b), id(c) {}
 19     bool operator < (const Q& cmp) const {
 20         return l > cmp.l;
 21     }
 22 };
 23 vector<Q> GS[55];
 24 int a[MAXN];
 25 lld sum[MAXN << 2];
 26 lld add[MAXN << 2];
 27 int n, m, q;
 28 lld out[MAXN];
 29 int log2[MAXN];
 30
 31 struct RMQ {
 32     int a[MAXN][22];
 33     void init(int A[], int N) {
 34         for (int i = 1; i <= N; i++) a[i][0] = A[i];
 35         for (int j = 1; (1 << j) <= N; j++) {
 36             for (int i = 1; i + j - 1 <= N; i++) {
 37                 a[i][j] = __gcd(a[i][j-1], a[i + (1<<(j-1))][j - 1]);
 38             }
 39         }
 40     }
 41     int rmq(int L, int R) {
 42       //  if (R < L) while (1);
 43         if (R < L) return 0;
 44         int k = log2[R - L + 1];
 45         return __gcd(a[L][k], a[R-(1<<k)+1][k]);
 46     }
 47 }AC;
 48
 49 /*     *segment tree*    */
 50 void build() {
 51     memset(add, 0, sizeof(add));
 52     memset(sum, 0, sizeof(sum));
 53 }
 54 void Down(int rt, int l, int r) {
 55     if (add[rt]) {
 56         int mid = r + l >> 1;
 57         add[rt<<1] += add[rt];
 58         add[rt<<1|1] += add[rt];
 59         sum[rt<<1] += (lld)(mid - l + 1) * add[rt];
 60         sum[rt<<1|1] += (lld)(r - mid) * add[rt];
 61         add[rt] = 0;
 62     }
 63     return ;
 64 }
 65 void Up(int rt) {
 66     sum[rt] = sum[rt<<1] + sum[rt<<1|1];
 67 }
 68 void update(int rt, int l, int r, int L, int R) {
 69     if (L > R) return ;
 70     if (l >= L && r <= R) {
 71         add[rt] += 1;
 72         sum[rt] += r - l + 1;
 73         return ;
 74     }
 75     Down(rt, l, r);
 76     int mid = r + l >> 1;
 77     if (mid >= L) update(lson, L, R);
 78     if (R > mid) update(rson, L, R);
 79     Up(rt);
 80 }
 81 lld query(int rt, int l, int r, int L, int R) {
 82     if (L > R) return 0LL;
 83     if (l >= L && r <= R) {
 84         return sum[rt];
 85     }
 86     Down(rt, l, r);
 87     int mid = r + l >> 1;
 88     lld ret = 0;
 89     if (mid >= L) ret += query(lson, L, R);
 90     if (R > mid) ret += query(rson, L, R);
 91     return ret;
 92 }
 93 /*     *segment tree*    */
 94
 95 PII arr[MAXN];
 96 void solve(vector<Q> vec, int M) {
 97     sort(vec.begin(), vec.end());
 98     build();
 99     int l = 1, r = 1;
100     for (int i = 1; i <= n; i++) {
101         if (a[i] % M != 0 || AC.rmq(i, n) % M == 0 && AC.rmq(i, n) > M) {
102             arr[i] = make_pair(-1, -1);
103         }else {
104             l = max(l, i); //r = max(r, i);
105             while (l <= n && AC.rmq(i, l) % M == 0 && AC.rmq(i, l) > M) ++ l;
106             r = max(l, r);
107             while (r+1 <= n && AC.rmq(i, r+1) == M) ++ r;
108             if (AC.rmq(i, l) == M) {
109                 arr[i] = make_pair(l, r);
110             }else {
111                 arr[i] = make_pair(-1, -1);
112             }
113         }
114     }
115     int now = n, siz = vec.size();
116     for (int i = 0; i < siz; i++) {
117         Q e = vec[i];
118         while (now >= 1 && e.l <= now) {
119             if (arr[now].first != -1) {
120                 update(1, 1, n, max(1, arr[now].first), arr[now].second);
121             }
122             -- now;
123         }
124         out[e.id] = query(1, 1, n, e.l, e.r);
125     }
126 }
127 /*
128
129 4 4 4
130 1 2 3 4
131 1 2 3 4
132 0 4 1
133 0 4 2
134 0 4 3
135 0 4 4
136
137 4 4 4
138 1 2 3 4
139 1 2 3 4
140 0 4 1
141 0 4 2
142 0 2 1
143 3 4 4
144
145 */
146
147 int gs[55];
148 int main() {
149     for (int i = 0; i < MAXN; i++) {
150         log2[i] = (i == 0 ? -1 : log2[i >> 1] + 1);
151     }
152     while (scanf("%d%d%d", &n, &m, &q) == 3) {
153         for (int i = 1; i <= n; i++) scanf("%d", &a[i]);
154         AC.init(a, n);
155         for (int i = 0; i < m; i++) scanf("%d", &gs[i]);
156         sort(gs, gs + m);
157         for (int i = 0; i < m; i++) GS[i].clear();
158         for (int i = 1; i <= q; i++) {
159             int l, r, x;
160             scanf("%d%d%d", &l, &r, &x);
161             x = lower_bound(gs, gs + m, x) - gs;
162             GS[x].push_back(Q(l + 1, r, i));
163         }
164         for (int i = 0; i < m; i++) {
165             solve(GS[i], gs[i]);
166         }
167         for (int i = 1; i <= q; i++) printf("%lld\n", out[i]);
168     }
169     return 0;
170 }

时间: 2024-08-25 17:30:30

ZOJ 5332 Calculation(离线 + 线段树)的相关文章

ZOJ 2859 二维线段树

思路:自己写的第二发二维线段树1A,哈哈,看来对二维的push操作比较了解了:但是还没遇到在两个线段树中同时进行push操作的,其实这题我是想在x维和y维同时进行push操作的,但是想了好久不会,然后看到这题又给出10秒,然后想想在x维线段直接单点查询肯定也过了,然后在第二维就只有pushup操作,在第一维线段树没有pushup操作.要是在第一维也有pushup操作的话,那就不用单点查询那么慢了.不过也A了,想找题即在二维同时进行pushup和pushdown操作的. #include<iost

hdu 4638 Group(莫队算法|离线线段树)

Group Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 1323    Accepted Submission(s): 703 Problem Description There are n men ,every man has an ID(1..n).their ID is unique. Whose ID is i and i-

HDU 4417 Super Mario(离线线段树or树状数组)

Problem Description Mario is world-famous plumber. His "burly" figure and amazing jumping ability reminded in our memory. Now the poor princess is in trouble again and Mario needs to save his lover. We regard the road to the boss's castle as a l

UPC 2224 Boring Counting (离线线段树,统计区间[l,r]之间大小在[A,B]中的数的个数)

题目链接:http://acm.upc.edu.cn/problem.php?id=2224 题意:给出n个数pi,和m个查询,每个查询给出l,r,a,b,让你求在区间l~r之间的pi的个数(A<=pi<=B,l<=i<=r). 参考链接:http://www.cnblogs.com/zj62/p/3558967.html #include <iostream> #include <cstdio> #include <cstring> #incl

27号的十道离线线段树

27号的十道离线线段树 hdu4288: (2012成都网络赛&&cf) #include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<algorithm> #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; const

POJ 2777 &amp;&amp; ZOJ 1610 &amp;&amp;HDU 1698 --线段树--区间更新

直接将这3题 放一起了  今天在做线段树的东西 这3个都是区间更新的 查询方式互相不同 反正都可以放到一起吧 直接先上链接了 touch me touch me touch me 关于涉及到区间的修改 -- 区间更新的话 分为 增减 或者 修改 主要就是个 laze 标记 就是延迟更新 对于区间更新的写法 一般是有2种 其一 仔细划分到每个细小的区间    另一 粗略划分 反正 ==我的代码里会给出2种写法 看自己喜好 hdu 1 //线段树 成段更新 ---> 替换 根结点的查询 2 3 #i

spoj gss2 : Can you answer these queries II 离线&amp;&amp;线段树

1557. Can you answer these queries II Problem code: GSS2 Being a completist and a simplist, kid Yang Zhe cannot solve but get Wrong Answer from most of the OI problems. And he refuse to write two program of same kind at all. So he always failes in co

HDU ACM 4417 Super Mario 离线线段树

分析:离线线段树,把所有询问离线读入,然后按H从小到大排序.对于所有结点也按从小到大排序,然后根据查询的H,将比H小的点加入到线段树,最后就是一个区间求和.这题貌似也可以用划分树,树状数组等方法做. #include<iostream> #include<algorithm> using namespace std; #define N 100005 struct Tree { int left,right,cnt; } TREE[N<<2]; struct Query

2333: [SCOI2011]棘手的操作[离线线段树]

2333: [SCOI2011]棘手的操作 Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 2325  Solved: 909[Submit][Status][Discuss] Description 有N个节点,标号从1到N,这N个节点一开始相互不连通.第i个节点的初始权值为a[i],接下来有如下一些操作: U x y: 加一条边,连接第x个节点和第y个节点 A1 x v: 将第x个节点的权值增加v A2 x v: 将第x个节点所在的连通块的所有