NOIp day2t2 借教室

线段树可以搞,思维难度确实小一些,但是复杂度可怕 O(mnlogn)

正解:差分+二分,复杂度(nlogm)且代码短。

总之,能用差分、前缀和、二分搞得尽量不要上线段树,代码长,常数还大,迫不得已再用。

 1 #include<iostream>
 2 #include<cstdio>
 3 #define mid (l+r>>1)
 4 using namespace std;
 5 typedef long long ll;
 6 
 7 const int Maxn = 1e6+10; 
 8 
 9 ll read(){
10     ll a = 0;char l = ' ',c = getchar();
11     while(c < '0'||c > '9')l = c,c = getchar();
12     while('0' <= c&&c <= '9')a = a*10+c-'0',c = getchar();
13     if(l == '-')return -a;return a;
14 }
15 
16 ll ql[Maxn],qr[Maxn],qc[Maxn],num[Maxn],cf[Maxn];
17 ll ans,l,r,n,m;
18 
19 bool check(int x){
20     for(int i = 1;i <= n;i++)cf[i] = num[i]-num[i-1];
21     for(int i = 1;i <= x;i++)cf[ql[i]] -= qc[i],cf[qr[i]+1] += qc[i];
22     ll now = 0;bool flag = true;
23     for(int i = 1;i <= n;i++){
24         now += cf[i];
25         if(now < 0){flag = false;break;}
26     }
27     return flag;
28 }
29 
30 int main(){
31     n = read(),m = read();
32     for(int i = 1;i <= n;i++)num[i] = read();
33     for(int i = 1;i <= m;i++)qc[i] = read(),ql[i] = read(),qr[i] = read();
34     l = 1,r = m;
35     while(l <= r)
36         if(check(mid))l = mid+1;
37         else ans = mid,r = mid-1;
38     if(ans)printf("-1
%d",ans);else putchar('0');    
39 return 0;
40 }
差分(100)
 1 #include<iostream>
 2 #include<cstdio>
 3 
 4 using namespace std;
 5 
 6 struct node{
 7     int l,r,w,laz,minx;
 8 }tree[4000010];
 9 
10 int read(){
11     int ans = 0;char last = ' ',ch = getchar();
12     while(ch < '0'||ch > '9')last = ch,ch = getchar();
13     while('0' <= ch&&ch <= '9')ans = ans*10+ch-'0',ch = getchar();
14     if(last == '-')return -ans;return ans; 
15 }
16 
17 void build(int d,int l,int r){
18     tree[d].l = l,tree[d].r = r;
19     if(l == r){
20         tree[d].minx = read();
21         return;
22     }
23     int mid = (l+r)/2;
24     build(d<<1,l,mid),build(d<<1|1,mid+1,r);
25     tree[d].minx = min(tree[d<<1].minx,tree[d<<1|1].minx);
26 }
27 
28 void down(int d){
29     tree[d<<1].minx += tree[d].laz;
30     tree[d<<1|1].minx += tree[d].laz;
31     tree[d<<1].laz += tree[d].laz;
32     tree[d<<1|1].laz += tree[d].laz;
33     tree[d].laz = 0;
34 }
35 
36 void change(int d,int l,int r,int x){//cout << d << ' ' << l << ' ' << r << endl;
37     //printf("%d %d
",tree[d].l,tree[d].r);
38     if(l <= tree[d].l&&tree[d].r <= r){
39         tree[d].laz += x;
40         tree[d].minx += x;
41         return;
42     }
43     down(d);
44     int mid = (tree[d].l+tree[d].r)>>1;
45     if(l <= mid)change(d<<1,l,r,x);
46     if(mid < r)change(d<<1|1,l,r,x);
47     tree[d].minx = min(tree[d<<1].minx,tree[d<<1|1].minx);
48 }
49 
50 int ask(int d,int l,int r){
51     int i = d;
52 //    printf("%d %d %d %d
",i,tree[i].l,tree[i].r,tree[i].minx);
53     if(l <= tree[d].l&&tree[d].r <= r)return tree[d].minx;
54     down(d);
55     int mid = (tree[d].l+tree[d].r)>>1,val = 0x7f;
56     if(l <= mid)val = min(val,ask(d<<1,l,r));
57     if(mid < r)val = min(val,ask(d<<1|1,l,r));
58     return val;
59 }
60 
61 int main(){
62     int n,m,x,y,z,val;
63     n = read(),m = read();
64     build(1,1,n);
65     for(int i = 1;i <= m;i++){
66         z = read(),x = read(),y = read();
67         change(1,x,y,-z);
68         val = ask(1,x,y);
69         if(val < 0){
70             printf("-1
%d",i);
71             return 0;
72         }
73     }
74     printf("0
");
75 return 0;
76 }
线段树(95分)
原文地址:https://www.cnblogs.com/Wangsheng5/p/11641601.html