53 条题解
-
8
刷题去 LV 10 @ 7 年前
线段树碰线过。。
-
37 年前@
坑点:
1.修改前缀和时要在上一个状态进行修改,不能从头到尾加
2.需要在一开始特判全都能过,否则一TLE一WA
3.并不需要开long long
还有一些细碎的二分之类,自己注意 -
27 年前@
一道较为基础的线段树题目。
大体的思路是每输入一组数据,用find函数查看一下是否可行;
如果可以,就调用add函数改变线段树中的数值;
如果不行,就输出-1,还有当前的申请序号,return 0;
如果一直没有return 0,说明都可以,输出0,return 0;
对于find函数大体思路:
区间最值与给的教室数大小关系的判断,都可以就可以,任何一个不行就都不行;
对于add函数大体思路:
当find发现可以借的时候才调用;
线段树对于区间最值的维护,对于符合的根节点tree[i]-=教室数;
并用lazy数组维护;
#include<iostream>
#include<algorithm>
#include<cstdio>
using namespace std;
int tree[24000010],a[600010],lazy[24000010],n,m,s,r,ans;
void read(int &x)
{
x=0;
char c=getchar();
while (c<'0'||c>'9') c=getchar();
while (c>='0'&&c<='9')
{
x=x*10+c-'0';
c=getchar();
}
}
void build(int x,int l,int r)
{
if (l==r)
{
tree[x]=a[l];
return;
}
int mid=(l+r)>>1;
build(x<<1,l,mid);
build(x<<1|1,mid+1,r);
tree[x]=min(tree[x<<1],tree[x<<1|1]);
}
void pushdown(int node,int l,int r)
{
tree[node<<1]+=lazy[node];
lazy[node<<1]+=lazy[node];
tree[node<<1|1]+=lazy[node];
lazy[node<<1|1]+=lazy[node];
lazy[node]=0;
}
void add(int node,int l,int r,int x,int y,int z)
{
if (l==x&&r==y)
{
tree[node]-=z;
lazy[node]-=z;
return;
}
if (lazy[node]) pushdown(node,l,r);
int mid=(l+r)>>1;
if (y<=mid)
add(node<<1,l,mid,x,y,z);
else
if (mid<x)
add(node<<1|1,mid+1,r,x,y,z);
else
{
add(node<<1,l,mid,x,mid,z);
add(node<<1|1,mid+1,r,mid+1,y,z);
}
tree[node]=min(tree[node<<1],tree[node<<1|1]);
}
bool find(int node,int l,int r,int x,int y,int z)
{
if(r==y&&x==l)
{
if (tree[node]>=z)
return true;
else
return false;
}
if (lazy[node]) pushdown(node,l,r);
int mid=(l+r)/2;
if (y<=mid)
return find(node<<1,l,mid,x,y,z);
else
if (x>mid)
return find(node<<1|1,mid+1,r,x,y,z);
else
return find(node<<1,l,mid,x,mid,z)&find(node<<1|1,mid+1,r,mid+1,y,z);
}
int main()
{
read(n);
read(m);
for(int i=1;i<=n;i++)
read(a[i]);
build(1,1,n);
for (int i=1;i<=m;i++)
{
int x,y,z;
read(z);
read(x);
read(y);
if (find(1,1,n,x,y,z))
{
add(1,1,n,x,y,z);
}
else
{
cout<<-1<<endl;
cout<<i<<endl;
return 0;
}
}
cout<<0<<endl;
} -
16 年前@
二分答案
知识准备:使用前缀数组处理数组区间标记,单点查询。
定义sum[i]=j ,假设我们要修改多个区间 [a,b],区间中每个元素都+c;然后我们询问每一个点,问值为多少?(N<=100w)
如果真正去标记区间[a,b]的话,时间复杂度为 O(n^2) ,显然不行。
那么我们就用一种特殊的方法来处理:
sum[a] + = c; sum[ b + 1 ] - = c;
然后我们从前到后对sum数组累加,每累加一次sum[i]就会得到点i的值。
前缀数组标记的时间复杂度为O(1),单点查询的复杂度为O(n);
借教室的题意分析:从前到后找到第一个不符合要求的订单即可!
也就是check (1,ans-1)==1;
而check (1,ans)==0的那个点ans。显然符合二分的思想,二分的是订单的编号,难点就是如何维护前缀数组sum[ ] ?
我们引入now变量,初值为0,记录当前sum数组中已经记录了从1到now的所有的订单的数据。Int mid=(l+r)>>1;
if(now<mid) 说明要把[now+1,mid]的订单加入到sum数组。
else(now>=mid) 说明要把[mid+1,now]的订单从sum数组中删除。
然后更新now=mid。
本题还有一个难点就是如何确定二分答案的左右端点!
左端点很好得出,可以为0或者1
右端点就有说道了,因为有一种情况是所有的订单都满足和第m个订单不满足情况的区别。
所有我们引入一个多余的空订单,即右端点r=m+1.
庆幸的是输出“0”的测试点并不多——防骗分。 -
17 年前@
二分答案
跑的飞起 -
17 年前@
二分答案。。。常数优化写不下去了就这样吧。。。交上去之后还挺快
依旧是循环展开+读入优化+寄存器变量,没啥新鲜的qwq就是这样
#1 Accepted 8ms 10.0MiB
#2 Accepted 7ms 10.0MiB
#3 Accepted 10ms 10.07MiB
#4 Accepted 10ms 10.094MiB
#5 Accepted 8ms 10.07MiB
#6 Accepted 10ms 10.0MiB
#7 Accepted 39ms 10.488MiB
#8 Accepted 45ms 10.469MiB
#9 Accepted 44ms 12.418MiB
#10 Accepted 48ms 16.051MiB
#11 Accepted 46ms 12.496MiB
#12 Accepted 43ms 14.527MiB
#13 Accepted 44ms 12.508MiB
#14 Accepted 45ms 14.598MiB
#15 Accepted 289ms 19.301MiB
#16 Accepted 317ms 19.305MiB
#17 Accepted 349ms 19.539MiB
#18 Accepted 367ms 19.406MiB
#19 Accepted 395ms 19.301MiB
#20 Accepted 393ms 19.305MiB比线段树要快
-
19 年前@
var a,ca,d,s,t:array[0..1000005] of longint;
i,j,k,l,n,m,r,o,now:longint;
tmt,ans:int64;
p:boolean;
begin
read(n,m);
for i:=1 to n do read(a[i]);
for i:=1 to m do read(d[i],s[i],t[i]);
d[m+1]:=a[1]+1; s[m+1]:=1; t[m+1]:=1;
l:=1; r:=m+1; now:=0;
while l<=r do
begin
ans:=l+((r-l) shr 1);
if ans>now then
for i:=now+1 to ans do
begin
inc(ca[s[i]],d[i]);
dec(ca[t[i]+1],d[i]);
end
else
for i:=ans+1 to now do
begin
dec(ca[s[i]],d[i]);
inc(ca[t[i]+1],d[i]);
end;
now:=ans;
tmt:=0;
p:=true;
for i:=1 to n do
begin
tmt:=tmt+ca[i];
if tmt>a[i] then begin p:=false; break; end;
end;
if p then l:=ans+1
else r:=ans-1;
end;
if l=m+1 then writeln(0)
else
begin
writeln(-1);
writeln(l);
end;
end.
数组把int64改成longint,最慢的从900+ms变成了600+ms,洛谷上更是从超时两个点到最慢的600+ms,告诉我为什么。
思路:恩二分的话不用讲,然后就是判断满不满足的部分。
用到了一个记录的数组,这个数组的性质是:ca[i]表示a[i]这个数比a[i-1]大ca[i],然后我想你已经知道了。
这个数组其实就是记录一个差值,然后使区间加减的复杂度变成了O(1),但是查询就是O(n)(查询一个和查询N个复杂度一样)。 -
02 周前@
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;struct node
{
int num,s,w;
}q[200010];struct node1
{
int num,s,w;
}win[100010];struct node2
{
int num,s,w;
}lose[100010];
int cmp(const node&x,const node&y)
{
if(x.s>y.s)
return 1;
if(x.s<y.s)
return 0;
return x.num<y.num;
}
int main()
{
int n,r,p,i,len1,len2;
scanf("%d%d%d",&n,&r,&p);
for(i=1;i<=2*n;i++)
scanf("%d",&q[i].s);
for(i=1;i<=2*n;i++)
{
q[i].num=i;
scanf("%d",&q[i].w);
}
sort(q+1,q+2*n+1,cmp);
while(r)
{
for(i=1;i<=n;i++)
if(q[2*i].w>q[2*i-1].w)
{
q[2*i].s++;
win[i].num=q[2*i].num;
win[i].s=q[2*i].s;
win[i].w=q[2*i].w;
lose[i].num=q[2*i-1].num;
lose[i].s=q[2*i-1].s;
lose[i].w=q[2*i-1].w;
}
else
{
q[2*i-1].s++;
win[i].num=q[2*i-1].num;
win[i].s=q[2*i-1].s;
win[i].w=q[2*i-1].w;
lose[i].num=q[2*i].num;
lose[i].s=q[2*i].s;
lose[i].w=q[2*i].w;
}
len1=1;
len2=1;
while(len1<=n&&len2<=n)
{
if(win[len1].s>lose[len2].s)
{
q[len1+len2-1].num=win[len1].num;
q[len1+len2-1].s=win[len1].s;
q[len1+len2-1].w=win[len1].w;
len1++;
}
if(win[len1].s<lose[len2].s)
{
q[len1+len2-1].num=lose[len2].num;
q[len1+len2-1].s=lose[len2].s;
q[len1+len2-1].w=lose[len2].w;
len2++;
}
if(win[len1].s==lose[len2].s)
if(win[len1].num<lose[len2].num)
{
q[len1+len2-1].num=win[len1].num;
q[len1+len2-1].s=win[len1].s;
q[len1+len2-1].w=win[len1].w;
len1++;
}
else
{
q[len1+len2-1].num=lose[len2].num;
q[len1+len2-1].s=lose[len2].s;
q[len1+len2-1].w=lose[len2].w;
len2++;
}
}
while(len1<=n)
{
q[len1+len2-1].num=win[len1].num;
q[len1+len2-1].s=win[len1].s;
q[len1+len2-1].w=win[len1].w;
len1++;
}
while(len2<=n)
{
q[len1+len2-1].num=lose[len2].num;
q[len1+len2-1].s=lose[len2].s;
q[len1+len2-1].w=lose[len2].w;
len2++;
}
r--;
}
printf("%d",q[p].num);
return 0;
} -
02 周前@
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int MAX = 1000000 + 2;
using namespace std;
int tree[MAX * 8];
int data[MAX];
int lazy[MAX * 8];
int n, m, tot;
void check(int rt)
{
if(tree[rt] < 0)
{
printf("-1\n%d", tot);
exit(0);
}
}
void up(int rt)
{
tree[rt] = min(tree[rt << 1] , tree[rt << 1 | 1]);
check(rt);
}
void built(int l, int r, int rt)
{
if(l == r)
{
tree[rt] = data[l];
return;
}
int m = l + (r - l) / 2;
built(l, m, rt << 1);
built(m + 1, r, rt << 1 | 1);
up(rt);
}
void down(int rt, int L, int R)
{
if(lazy[rt])
{
int m = L + (R - L) / 2;lazy[rt * 2] += lazy[rt];
lazy[rt * 2 + 1] += lazy[rt];
tree[rt * 2] -= lazy[rt];
tree[rt * 2 + 1] -= lazy[rt];
lazy[rt] = 0;
}
}
void modify(int L, int R, int l, int r, int val, int rt)
{if(L >= l && R <= r)
{
tree[rt] -= val;
check(rt);
lazy[rt] += val;
return;
}
check(rt);
down(rt, L, R);
int m = L + (R - L) / 2;
if(m >= l) modify(L, m, l, r, val, rt * 2);
if(m < r) modify(m + 1, R, l, r, val, rt * 2 + 1);
up(rt);
}
void solve(int n, int m)
{
int a, b, c;
for(int i = 1; i <= m; i++)
{
tot = i;
scanf("%d %d %d", &c, &a, &b);
modify(1, n, a, b, c, 1);
}
printf("0");
return;
}
void init(int n, int m)
{for(int i = 1; i <= n; i++)
scanf("%d", &data[i]);
built(1, n, 1);
}
int main()
{
// freopen("in.txt","r", stdin);
scanf("%d %d", &n, &m);
init(n, m);
solve(n, m);
return 0;
} -
06 年前@
每个测试点不止1秒?
-
07 年前@
差分+二分答案
就完事了
-
07 年前@
Lazy线段树,1234ms居然没TLE
状态 耗时 内存占用
#1 Accepted 4ms 380.0 KiB
#2 Accepted 4ms 348.0 KiB
#3 Accepted 3ms 384.0 KiB
#4 Accepted 4ms 372.0 KiB
#5 Accepted 4ms 360.0 KiB
#6 Accepted 4ms 348.0 KiB
#7 Accepted 42ms 3.219 MiB
#8 Accepted 57ms 3.734 MiB
#9 Accepted 76ms 3.836 MiB
#10 Accepted 96ms 2.375 MiB
#11 Accepted 104ms 2.859 MiB
#12 Accepted 116ms 2.492 MiB
#13 Accepted 150ms 4.25 MiB
#14 Accepted 116ms 3.082 MiB
#15 Accepted 440ms 18.121 MiB
#16 Accepted 619ms 17.84 MiB
#17 Accepted 859ms 17.824 MiB
#18 Accepted 943ms 16.742 MiB
#19 Accepted 1185ms 18.117 MiB
#20 Accepted 1234ms 18.461 MiB -
07 年前@
二分:
线段树:
-
07 年前@
2分
Segment Tree
-
07 年前@
2012NOIP DAY2T1
方法1:线段树
使用线段树来维护一个区间的最小值,每次对于输入的L,R区间进行区间修改,如果最小值<0,则无法成功借教室(加了一大堆玄学优化,终于勉强没T)方法2:二分+差分
二分能够成功的方案数,用差分进行区修改,暴力判断有没有超出限制的,时间复杂度O(nlogn)
其实跟线段树的复杂度相同,只是常数比较小,在数据爆炸的题里会快不少! -
07 年前@
一击!!!
-
08 年前@
两件事情:
1.被卡时限的首先优化读入。
2.结构体、类封装、位运算加速在这道题里面对于程序运行时间影响很小。编译成功
测试数据 #0: Accepted, time = 46 ms, mem = 47528 KiB, score = 5
测试数据 #1: Accepted, time = 46 ms, mem = 47524 KiB, score = 5
测试数据 #2: Accepted, time = 31 ms, mem = 47524 KiB, score = 5
测试数据 #3: Accepted, time = 31 ms, mem = 47528 KiB, score = 5
测试数据 #4: Accepted, time = 31 ms, mem = 47524 KiB, score = 5
测试数据 #5: Accepted, time = 46 ms, mem = 47524 KiB, score = 5
测试数据 #6: Accepted, time = 93 ms, mem = 47528 KiB, score = 5
测试数据 #7: Accepted, time = 46 ms, mem = 47528 KiB, score = 5
测试数据 #8: Accepted, time = 62 ms, mem = 47528 KiB, score = 5
测试数据 #9: Accepted, time = 93 ms, mem = 47528 KiB, score = 5
测试数据 #10: Accepted, time = 93 ms, mem = 47524 KiB, score = 5
测试数据 #11: Accepted, time = 125 ms, mem = 47524 KiB, score = 5
测试数据 #12: Accepted, time = 125 ms, mem = 47524 KiB, score = 5
测试数据 #13: Accepted, time = 78 ms, mem = 47524 KiB, score = 5
测试数据 #14: Accepted, time = 437 ms, mem = 47528 KiB, score = 5
测试数据 #15: Accepted, time = 609 ms, mem = 47524 KiB, score = 5
测试数据 #16: Accepted, time = 734 ms, mem = 47524 KiB, score = 5
测试数据 #17: Accepted, time = 875 ms, mem = 47528 KiB, score = 5
测试数据 #18: Accepted, time = 1000 ms, mem = 47524 KiB, score = 5
测试数据 #19: Accepted, time = 1171 ms, mem = 47528 KiB, score = 5#include<bits/stdc++.h>
using namespace std;
struct INTERVAL_DATA{
int left,right,Max,lazy;
INTERVAL_DATA(){
left=right=0;
lazy=0;
Max=0;
}
};
INTERVAL_DATA tree[3000000];
inline int read( )
{
int x=0;
char ch=getchar();
while (ch<'0'||ch>'9') ch=getchar();
x=0;
while (ch<='9' && ch>='0')
{
x*=10,x+=ch-'0';
ch=getchar();
}
return x;
}
struct INTERVAL_TREE{
int nn;
INTERVAL_TREE(int height){
nn=height;int h=0;
tree[0].left=0;tree[0].right=(1<<nn)-1;
for (int i=0;i<((1<<nn)-1);i++){
if (i>(2<<h)-2) h++;
tree[(i<<1)+1].left=tree[i].left;
tree[(i<<1)+2].left=(1<<(nn-h-1))|tree[i].left;
tree[(i<<1)+1].right=tree[(i<<1)+1].left+(1<<(nn-h-1))-1;
tree[(i<<1)+2].right=tree[(i<<1)+2].left+(1<<(nn-h-1))-1;
}
for (int i=0;i<(2<<nn)-1;i++){
tree[i].left++;
tree[i].right++;
}
}
void add(int root,int l,int r,int x){
if (l==tree[root].left&&r==tree[root].right) tree[root].lazy+=x;
else {
int mid=(tree[root].left+tree[root].right)>>1;
tree[(root<<1)+1].lazy+=tree[root].lazy;
tree[(root<<1)+2].lazy+=tree[root].lazy;
tree[root].lazy=0;if (l>mid) add((root<<1)+2,l,r,x);
else if (r<=mid) add((root<<1)+1,l,r,x);
else {
add((root<<1)+1,l,mid,x);
add((root<<1)+2,mid+1,r,x);
}tree[root].Max=max(tree[(root<<1)+1].lazy+tree[(root<<1)+1].Max,tree[(root<<1)+2].lazy+tree[(root<<1)+2].Max);
}
}
} a(20);
int main(){
int n,m,x,y,z;
n = read();
m = read();
for (int i=0;i<n;i++){
x = read();
a.add(0,i+1,i+1,-x);
}for (int i=0;i<m;i++){
x=read();
y=read();
z=read();
a.add(0,y,z,x);
if (tree[0].Max>0) {
cout<<"-1"<<endl<<i+1<<endl;
return 0;
}
}cout<<0<<endl;
return 0;
} -
09 年前@
论**普通线段树**如何通过
关键在于各种**奇技淫巧的优化**,我列出一些:
1. 正确的模拟方法 +30%
2. 堆式存储 +15%
3. 将所有除以2的运算变为位运算 +3%
4. 手动优化尾递归,vijos没有开优化 +5%
5. 循环使用迭代器写法 +5%
6. 读入优化 +3%
7. 大胆的使用int +2%
8. 使用结构体的默认构造函数 +1%
9. 线段树的插入和查询操作中对每条语句的必要性进行严格检查。删去没必要的语句 +2%优化真是一件有趣的事......
实在过不了的可以到codevs上试试,codevs的机子好多了......代码:
```c++
// 借教室#include <cstdlib>
#include <string>
#include <cstdio>
#include <algorithm>using namespace std;
#define NMAX 1000000
#define MMAX 1000000
#define MEMORY_SIZE 2097151#define LEFT(x) (x << 1)
#define RIGHT(x) ((x << 1) | 1)
#define PARENT(x) (x >> 1)// #define FMT "%lld"
// typedef long long ntype;
#define FMT "%d"
typedef int ntype;struct Reservation {
Reservation() : start(0), end(0), need(0) {}
Reservation(ntype s, ntype t, ntype d) : start(s), end(t), need(d) {}ntype start;
ntype end;
ntype need;
}; // struct Reservationstruct Node {
Node() : pos(1), l(0), r(0), sum(0) {}
Node(ntype _l, ntype _r) : pos(1), l(_l), r(_r), sum(0) {}ntype pos;
ntype l;
ntype r;
ntype sum;
};static ntype n, m;
static ntype r[NMAX + 10];
static Reservation q[MMAX + 10];
static Node heap[MEMORY_SIZE];
static bool flag;
static ntype id;Node *build_tree(ntype lb, ntype rb, ntype p = 1);
void insert(ntype s, ntype t, ntype value, ntype p = 1);
ntype query(ntype d, ntype p = 1);inline ntype read() {
ntype x = 0;
char c = getchar();
while (c < '0' or c > '9') c = getchar();
while ('0' <= c and c <= '9') x = x * 10 + c - '0', c = getchar();
return x;
}void initialize();
void quit();int main() {
initialize();for (Reservation *beg = &q[1]; beg != &q[n + 1]; beg++) {
insert(beg->start, beg->end, -beg->need, 1);
} // forReservation *j = &q[m + 1];
for (ntype i = 1; i <= n; i++) {
while (query(i, 1) < 0) {
j--;
insert(j->start, j->end, j->need, 1);
} // while
} // forif (j != &q[m + 1]) {
flag = true;
id = j - &q[1] + 1;
}quit();
return 0;
} // function mainvoid initialize() {
n = read();
m = read();for (int *beg = &r[1]; beg != &r[n + 1]; beg++) *beg = read();
for (Reservation *beg = &q[1]; beg != &q[m + 1]; beg++)
beg->need = read(), beg->start = read(), beg->end = read();flag = false;
id = 0;build_tree(1, n);
}void quit() {
if (!flag)
puts("0");
else {
puts("-1");
printf(FMT, id);
}
}Node *build_tree(ntype lb, ntype rb, ntype p) {
Node *x = &heap[p];
x->l = lb;
x->r = rb;if (lb != rb) {
ntype mid = (lb + rb) >> 1;
build_tree(lb, mid, LEFT(p));
build_tree(mid + 1, rb, RIGHT(p));
} else
x->sum = r[lb];return x;
}void insert(ntype s, ntype t, ntype value, ntype p) {
recursive:
Node *x = &heap[p];if (s <= x->l and x->r <= t)
x->sum += value;
else {
ntype mid = (x->l + x->r) >> 1;if (t <= mid) {
// insert(s, t, value, LEFT(p));
p = LEFT(p);
goto recursive;
} else if (s > mid) {
// insert(s, t, value, RIGHT(p));
p = RIGHT(p);
goto recursive;
} else {
insert(s, t, value, LEFT(p));
insert(s, t, value, RIGHT(p));
}
}
}ntype query(ntype d, ntype p) {
ntype result = 0;recursive:
Node *x = &heap[p];if (d == x->l and d == x->r) return result + x->sum;
result += x->sum;
ntype mid = (x->l + x->r) >> 1;if (d <= mid)
p = LEFT(p);
else
p = RIGHT(p);goto recursive;
} -
09 年前@
你们也交交看,一样的程序有时AC有时TLE
评测结果
编译成功测试数据 #0: Accepted, time = 0 ms, mem = 317268 KiB, score = 5
测试数据 #1: Accepted, time = 0 ms, mem = 317268 KiB, score = 5
测试数据 #2: Accepted, time = 15 ms, mem = 317272 KiB, score = 5
测试数据 #3: Accepted, time = 0 ms, mem = 317272 KiB, score = 5
测试数据 #4: Accepted, time = 0 ms, mem = 317268 KiB, score = 5
测试数据 #5: Accepted, time = 0 ms, mem = 317272 KiB, score = 5
测试数据 #6: Accepted, time = 31 ms, mem = 317268 KiB, score = 5
测试数据 #7: Accepted, time = 31 ms, mem = 317268 KiB, score = 5
测试数据 #8: Accepted, time = 46 ms, mem = 317272 KiB, score = 5
测试数据 #9: Accepted, time = 78 ms, mem = 317272 KiB, score = 5
测试数据 #10: Accepted, time = 78 ms, mem = 317268 KiB, score = 5
测试数据 #11: Accepted, time = 93 ms, mem = 317272 KiB, score = 5
测试数据 #12: Accepted, time = 140 ms, mem = 317272 KiB, score = 5
测试数据 #13: Accepted, time = 78 ms, mem = 317268 KiB, score = 5
测试数据 #14: Accepted, time = 437 ms, mem = 317272 KiB, score = 5
测试数据 #15: Accepted, time = 703 ms, mem = 317272 KiB, score = 5
测试数据 #16: Accepted, time = 937 ms, mem = 317272 KiB, score = 5
测试数据 #17: Accepted, time = 1218 ms, mem = 317272 KiB, score = 5
测试数据 #18: Accepted, time = 1500 ms, mem = 317272 KiB, score = 5
测试数据 #19: Accepted, time = 1625 ms, mem = 317272 KiB, score = 5
Accepted, time = 7010 ms, mem = 317272 KiB, score = 100
代码
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,a[1000003],p,tot;
int d,s,t;
struct arr{
int w,c;
}tr[1000003*40];int read(){
int f=1,x=0;
char s=getchar();
while(s<'0'||s>'9') s=getchar();
while(s>='0' && s<='9'){
x=x*10+(s-48);
s=getchar();
}
return f*x;
}void push(int num){
tr[2*num].c+=tr[num].c;
tr[2*num+1].c+=tr[num].c;
tr[num].w-=tr[num].c;
tr[num].c=0;
}void build(int num,int l,int r){
if (l==r){
tr[num].w=a[l];
return;
}
build(2*num,l,(l+r)/2);
build(2*num+1,(l+r)/2+1,r);
tr[num].w=min(tr[2*num].w,tr[2*num+1].w);
}int find(int num,int l,int r){
if (tr[num].c) push(num);
if (l>t || r<s || l>r) return 2147483647;
if (s<=l && r<=t) return tr[num].w;
return min(find(2*num,l,(l+r)/2),find(2*num+1,(l+r)/2+1,r));
}void insert(int num,int l,int r){
if (tr[num].c) push(num);
if (l>t || r<s || l>r) return;
if (s<=l && r<=t){
tr[num].w-=d;
tr[2*num].c+=d;
tr[2*num+1].c+=d;
return;
}
insert(2*num,l,(l+r)/2);
insert(2*num+1,(l+r)/2+1,r);
tr[num].w=min(tr[2*num].w,tr[2*num+1].w);
}int main(){
n=read();m=read();
for (int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
for (int i=1;i<=m;i++){
d=read();s=read();t=read();
if (tot) continue;
int dd=find(1,1,n);
if (dd<d) p=i,tot++;
else insert(1,1,n);
}
if (tot) printf("-1\n%d\n",p);
else printf("0\n");
return 0;
}评测结果
编译成功测试数据 #0: Accepted, time = 0 ms, mem = 317272 KiB, score = 5
测试数据 #1: Accepted, time = 0 ms, mem = 317276 KiB, score = 5
测试数据 #2: Accepted, time = 0 ms, mem = 317272 KiB, score = 5
测试数据 #3: Accepted, time = 0 ms, mem = 317276 KiB, score = 5
测试数据 #4: Accepted, time = 15 ms, mem = 317276 KiB, score = 5
测试数据 #5: Accepted, time = 0 ms, mem = 317272 KiB, score = 5
测试数据 #6: Accepted, time = 31 ms, mem = 317276 KiB, score = 5
测试数据 #7: Accepted, time = 62 ms, mem = 317272 KiB, score = 5
测试数据 #8: Accepted, time = 78 ms, mem = 317272 KiB, score = 5
测试数据 #9: Accepted, time = 124 ms, mem = 317276 KiB, score = 5
测试数据 #10: Accepted, time = 124 ms, mem = 317272 KiB, score = 5
测试数据 #11: Accepted, time = 156 ms, mem = 317272 KiB, score = 5
测试数据 #12: Accepted, time = 187 ms, mem = 317276 KiB, score = 5
测试数据 #13: Accepted, time = 140 ms, mem = 317276 KiB, score = 5
测试数据 #14: Accepted, time = 873 ms, mem = 317272 KiB, score = 5
测试数据 #15: Accepted, time = 1341 ms, mem = 317272 KiB, score = 5
测试数据 #16: Accepted, time = 1700 ms, mem = 317276 KiB, score = 5
测试数据 #17: TimeLimitExceeded, time = 2012 ms, mem = 317276 KiB, score = 0
测试数据 #18: TimeLimitExceeded, time = 2012 ms, mem = 317276 KiB, score = 0
测试数据 #19: TimeLimitExceeded, time = 2012 ms, mem = 317276 KiB, score = 0
TimeLimitExceeded, time = 10867 ms, mem = 317276 KiB, score = 85
代码
#include <cstring>
#include <cstdio>
#include <algorithm>
using namespace std;
int n,m,a[1000003],p,tot;
int d,s,t;
struct arr{
int w,c;
}tr[1000003*40];int read(){
int f=1,x=0;
char s=getchar();
while(s<'0'||s>'9') s=getchar();
while(s>='0' && s<='9'){
x=x*10+(s-48);
s=getchar();
}
return f*x;
}void push(int num){
tr[2*num].c+=tr[num].c;
tr[2*num+1].c+=tr[num].c;
tr[num].w-=tr[num].c;
tr[num].c=0;
}void build(int num,int l,int r){
if (l==r){
tr[num].w=a[l];
return;
}
build(2*num,l,(l+r)/2);
build(2*num+1,(l+r)/2+1,r);
tr[num].w=min(tr[2*num].w,tr[2*num+1].w);
}int find(int num,int l,int r){
if (tr[num].c) push(num);
if (l>t || r<s || l>r) return 2147483647;
if (s<=l && r<=t) return tr[num].w;
return min(find(2*num,l,(l+r)/2),find(2*num+1,(l+r)/2+1,r));
}void insert(int num,int l,int r){
if (tr[num].c) push(num);
if (l>t || r<s || l>r) return;
if (s<=l && r<=t){
tr[num].w-=d;
tr[2*num].c+=d;
tr[2*num+1].c+=d;
return;
}
insert(2*num,l,(l+r)/2);
insert(2*num+1,(l+r)/2+1,r);
tr[num].w=min(tr[2*num].w,tr[2*num+1].w);
}int main(){
n=read();m=read();
for (int i=1;i<=n;i++) a[i]=read();
build(1,1,n);
for (int i=1;i<=m;i++){
d=read();s=read();t=read();
if (tot) continue;
int dd=find(1,1,n);
if (dd<d) p=i,tot++;
else insert(1,1,n);
}
if (tot) printf("-1\n%d\n",p);
else printf("0\n");
return 0;
} -
09 年前@
线段树 !!经典模板
http://www.ofsxb.com/archives/455