题目就不放了,占空间
然后找了一个官方题解,开始有点看不懂,后来懂了
看别人的题解都说题目好懂,然而并不觉得,我做了一段时间才发现自己连题目都理解错了。
题目意思:
有n个塔,每个塔最多攻击一次,造成d伤害,攻击区间为L到R,然后有k个怪兽,分别在不同的点上,它们要走到n点(最右边的点),问有多少个怪物存活。
一开始一直没看到怪物走向n点的条件,怎么都看不懂。
然后,想到的普通做法就是,根据塔的信息进行区间更新,将区间的值加上伤害值。
由于所有怪要走到n点,所以我们开一个后缀和数组,记录每个点到n点的shan伤害值,最后回答询问。
如果用普通的线段树做法,是n*log(n)的算法,很遗憾,会超时,md,这样算法都超时,真够坑的啊。
然后优化的做法是,对于区间更新,只需要差分一下,这里就有个小知识点了,更新区间的值,只需要把左端点值+val,右端点右边一个点-val,然后扫一遍相加就能求出每个点的值,这个知识点,只要做过线段树的都应该知道吧
AC的代码(真的都懒得打):
//#pragma warning (disable:4786)
#include <cstdio>
#include <cmath>
#include <cstring>
#include <string>
#include <cstdlib>
#include <queue>
#include <stack>
#include <vector>
#include <iostream>
#include <algorithm>
using namespace std;
#define INF 1e18
typedef __int64 LL;
const int MAXN = 200017;
int num[MAXN];
LL sum[MAXN];
int main()
{
int l,r,d;
int tow,n,m,x;
LL h;
while(scanf("%d",&n) && n)
{
scanf("%d",&tow);
memset(num,0,sizeof(num));
memset(sum,0,sizeof(sum));
for(int i = 0; i < tow; i++)
{
scanf("%d%d%d",&l,&r,&d);
num[l] += d;
num[r+1] -= d;
}
for(int i = 1; i <= n; i++)
{
sum[i] = sum[i-1]+num[i];
}
for(int i = n; i >= 1; i--)
{
sum[i] = sum[i+1]+sum[i];
}
int cont = 0;
scanf("%d",&m);
for(int i = 0; i < m; i++)
{
scanf("%I64d%d",&h,&x);
if(sum[x] < h)
{
cont++;
}
}
printf("%d\n",cont);
}
return 0;
}
下面是TLE的代码:
我更愿意写这个版本的,接地气
#include<cstdio>
#include<cstring>
#include<vector>
#include<iostream>
typedef long long ll;
#define fori(l,r) for( int i = l ; i <= r ; i++ )
#define forj(l,r) for( int j = l ; j <= r ; j++ )
#define fork(l,r) for( int k = 1 ; k <= r ; k++ )
#define mem(a,val) memset(a,val,sizeof a)
#define lef rt<<1
#define rig rt<<1|1
#define mid (l+r)>>1
using namespace std;
const int maxn = 1e5+5;
ll tree[maxn<<2],add[maxn<<2];
int n,m;
int L,R;
ll backsum[maxn];
int read( )
{
char ch = getchar();
int x = 0;
while( ch < '0' || ch >'9' )
ch = getchar();
while( ch >= '0' && ch <= '9' )
{
x = x*10+ch-'0';
ch = getchar();
}
return x;
}
ll longread( )
{
char ch = getchar();
ll x = 0;
while( ch < '0' || ch >'9' )
ch = getchar();
while( ch >= '0' && ch <= '9' )
{
x = x*10+ch-'0';
ch = getchar();
}
return x;
}
void pushdown( int rt )
{
if( add[rt] )
{
tree[lef] += add[rt];
tree[rig] += add[rt];
add[lef] += add[rt];
add[rig] += add[rt];
add[rt] = 0;
}
}
void change( int rt )
{
tree[rt] = tree[lef]+tree[rig];
}
void update( int l,int r,int rt,ll val )
{
if( l >= L && r <= R )
{
tree[rt] += val;
add[rt] += val;
return;
}
pushdown(rt);
int m = mid;
if( m >= L )
update(l,m,lef,val);
if( m < R )
update(m+1,r,rig,val);
//change(rt);
}
ll query( int l,int r,int rt,int pos ) //单点查询
{
if( l == r )
return tree[rt];
int m = mid;
pushdown(rt);
if( m >= pos )
return query(l,m,lef,pos);
else return query(m+1,r,rig,pos);
}
int main()
{
while( scanf("%d",&n) == 1 && n )
{
ll d;
//scanf("%d",&m);
m = read();
int rr = n<<2;
fori(1,rr)
{
tree[i] = 0;
add[i] = 0;
}
//fori(1,m)
for( int i = 1 ; i <= m ; i++ )
{
L = read();
R = read();
d = longread();
//scanf("%d %d %I64d",&L,&R,&d);
update(1,n,1,d);
}
ll total = 0;
for( int i = n ; i >= 1 ; i-- )
{
total += query(1,n,1,i);
backsum[i] = total;
//cout<<backsum[i]<<" ";
}
int k,pos,ans = 0;
ll hp;
scanf("%d",&k);
while( k-- )
{
hp = longread();
pos = read();
//scanf("%I64d %d",&hp,&pos);
if( backsum[pos] < hp ) //造成的伤害小于hp 则存活
ans++;
}
printf("%d\n",ans);
}
return 0;
}
/*
5 5
1 3 1
2 4 2
4 5 1
3 5 4
1 2 2
7
5 3
4 2
5 5
5 1
4 4
4 3
7 2
5 5
1 3 1
2 4 2
4 5 1
3 5 4
1 2 2
7
8 3
4 2
9 5
5 1
5 4
7 3
7 2
5 5
1 3 3
2 4 5
4 5 6
3 5 4
1 2 2
7
8 3
4 3
9 5
7 2
12 4
7 3
14 2
*/