传送门

A. Greg and Array
time limit per test   1.5 seconds
memory limit per test   256 megabytes
input   standard input
output  standard output

Greg has an array a = a1, a2, ..., an and m operations. Each operation looks as: li, ri, di, (1 ≤ li ≤ ri ≤ n). To apply operation i to the array means to increase all array elements with numbers li, li + 1, ..., ri by value di.

Greg wrote down k queries on a piece of paper. Each query has the following form: xi, yi, (1 ≤ xi ≤ yi ≤ m). That means that one should apply operations with numbers xi, xi + 1, ..., yi to the array.

Now Greg is wondering, what the array a will be after all the queries are executed. Help Greg.

Input

The first line contains integers n, m, k (1 ≤ n, m, k ≤ 105). The second line contains n integers: a1, a2, ..., an(0 ≤ ai ≤ 105) — the initial array.

Next m lines contain operations, the operation number i is written as three integers: li, ri, di, (1 ≤ li ≤ ri ≤ n), (0 ≤ di ≤ 105).

Next k lines contain the queries, the query number i is written as two integers: xi, yi, (1 ≤ xi ≤ yi ≤ m).

The numbers in the lines are separated by single spaces.

Output

On a single line print n integers a1, a2, ..., an — the array after executing all the queries. Separate the printed numbers by spaces.

Please, do not use the %lld specifier to read or write 64-bit integers in C++. It is preferred to use the cin, cout streams of the %I64d specifier.

Sample test(s)
Input
3 3 3
1 2 3
1 2 1
1 3 2
2 3 4
1 2
1 3
2 3
Output
9 18 17
Input
1 1 1
1
1 1 1
1 1
Output
2
Input
4 3 6
1 2 3 4
1 2 1
2 3 2
3 4 4
1 2
1 3
2 3
1 2
1 3
2 3
Output
5 18 31 20

分析
线段树
离线预处理所有Query,统计各operation的次数。
区间Insert,注意使用lazy-tag,点Query答案。
写法
要维护两棵线段树,可并做一棵。

这是我第一次写的,TLE on test 24
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAX_N=1e5+10;
 4 typedef long long ll;
 5 
 6 struct op{
 7     int l, r;
 8     ll v;
 9 }o[MAX_N];
10 
11 ll cnt[MAX_N], a[MAX_N];
12 
13 struct Node{
14     int l, r;
15     ll v;
16     int mid(){return (l+r)>>1;}
17 }T[MAX_N<<2];
18 
19 void Build(int id, int l, int r){
20     T[id].l=l, T[id].r=r, T[id].v=0;
21     if(l==r) return;
22     int mid=T[id].mid();
23     Build(id<<1, l, mid);
24     Build(id<<1|1, mid+1, r);
25 }
26 void Insert(int id, int l, int r, ll v){
27     Node &now=T[id];
28     if(now.l>=l&&now.r<=r){
29         if(~now.v) now.v+=v;
30         else{
31             Insert(id<<1, l, r, v);
32             Insert(id<<1|1, l, r, v);
33         }
34     }
35     else{
36         Node &lch=T[id<<1], &rch=T[id<<1|1];
37         if(~now.v) lch.v=rch.v=now.v, now.v=-1; //ERROR-PRONE
38         int mid=now.mid();
39         if(l<=mid) Insert(id<<1, l, r, v);
40         if(r>mid) Insert(id<<1|1, l, r, v);
41         if(lch.v==rch.v) now.v=lch.v;
42     }
43 }
44 
45 void Qurery(int id, ll *a){
46     Node &now=T[id];
47     if(~now.v)
48         for(int i=now.l; i<=now.r; i++) a[i]+=now.v;
49     else{
50         Qurery(id<<1, a);
51         Qurery(id<<1|1, a);
52     }
53 }
54 
55 int main(){
56     //freopen("in", "r", stdin);
57     int N, M, K;
58     scanf("%d%d%d", &N, &M, &K);
59     for(int i=1; i<=N; i++) scanf("%lld", a+i);
60     for(int i=1; i<=M; i++)
61         scanf("%d%d%lld", &o[i].l, &o[i].r, &o[i].v);
62     Build(1, 1, M);
63     int l, r;
64     while(K--){
65         scanf("%d%d", &l, &r);
66         Insert(1, l, r, 1);
67     }
68     Qurery(1, cnt);
69     Build(1, 1, N);
70     for(int i=1; i<=M; i++)
71         if(cnt[i])
72             Insert(1, o[i].l, o[i].r, o[i].v*cnt[i]);
73     Qurery(1, a);
74     for(int i=1; i<=N; i++)
75         printf("%lld ", a[i]);
76     puts("");
77     return 0;
78 }

 

上面的代码没有lazy-tag或者说我设置的lazy-tag没起到相应的作用。我的考虑是设置一个tag,最后求答案时可不必细分到每个叶子节点,但是这种优化对降低Insert的复杂度没有太大帮助,而Insert是最耗时的,因而总的复杂度还是没降下来。
AC的姿势
 1 #include<bits/stdc++.h>
 2 using namespace std;
 3 const int MAX_N=1e5+10;
 4 typedef long long ll;
 5 
 6 struct op{
 7     int l, r, v;
 8 }o[MAX_N];
 9 
10 ll cnt[MAX_N], a[MAX_N];
11 
12 struct Node{
13     int l, r;
14     ll v;
15     int mid(){return (l+r)>>1;}
16 }T[MAX_N<<2];
17 
18 void Build(int id, int l, int r){
19     T[id].l=l, T[id].r=r, T[id].v=0;
20     if(l==r) return;
21     int mid=T[id].mid();
22     Build(id<<1, l, mid);
23     Build(id<<1|1, mid+1, r);
24 }
25 void Insert(int id, int l, int r, ll v){
26     Node &now=T[id];
27     if(now.l>=l&&now.r<=r) now.v+=v;
28     else{
29         Node &lch=T[id<<1], &rch=T[id<<1|1];
30         if(now.v) 
31             lch.v+=now.v, rch.v+=now.v, now.v=0;
32         int mid=now.mid();
33         if(l<=mid) Insert(id<<1, l, r, v);
34         if(r>mid) Insert(id<<1|1, l, r, v);
35     }
36 }
37 
38 void Qurery(int id, ll *a){
39     Node &now=T[id];
40     if(now.l==now.r) a[now.l]+=now.v;
41     else{
42         Node &lch=T[id<<1], &rch=T[id<<1|1];
43         if(now.v) 
44             lch.v+=now.v, rch.v+=now.v;
45         Qurery(id<<1, a);
46         Qurery(id<<1|1, a);
47     }
48 }
49 
50 int main(){
51     //freopen("in", "r", stdin);
52     int N, M, K;
53     scanf("%d%d%d", &N, &M, &K);
54     for(int i=1; i<=N; i++) scanf("%lld", a+i);
55     for(int i=1; i<=M; i++)
56         scanf("%d%d%lld", &o[i].l, &o[i].r, &o[i].v);
57     Build(1, 1, M);
58     int l, r;
59     while(K--){
60         scanf("%d%d", &l, &r);
61         Insert(1, l, r, 1);
62     }
63     Qurery(1, cnt);
64     Build(1, 1, N);
65     for(int i=1; i<=M; i++)
66         if(cnt[i]&&o[i].v)
67             Insert(1, o[i].l, o[i].r, o[i].v*cnt[i]);
68     Qurery(1, a);
69     for(int i=1; i<=N; i++)
70         printf("%lld ", a[i]);
71     puts("");
72     return 0;
73 }

 

 

 

 

 

相关文章: