对于这道题,如果按照朴素算法来说,第一反应是对于每个位置i的糖糖,处理1 ~ i-1 被消灭的糖糖有哪些,给他们标记,然后最后统计一遍,很显然,这样复杂度很高,不足以通过这道题,所以我们换种处理方法。
先看m次操作,有影响的一定是 ,我们可以维护一个前缀和,
表示第
项前面有几次操作,这样做的意义是什么呢,对于
表示位置
的糖糖比位置
多了几次赋值
的操作。
对于每个位置i的糖糖,我们考虑是否会被击杀,我们可以发现,当且仅当 位置存在和糖糖
不是一队且
的时候,位置
的糖糖才会被击败,将式子移项即可发现,
,所以我们可以维护这个式子的最大值即可,由于是维护
到
的最大值,所以只需要倒着扫描数组即可,计算不能被击败的有几个,输出即可,由于题目限制队伍
,所以只需要用两个变量维护就行。
#include <cstring>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <map>
#include<time.h>
#define ll long long
using namespace std;
const int maxn=2e5+10,INF=0x3f3f3f3f;
int B[maxn],Csum[maxn],team[maxn],Max[2];
struct node {
int Left,Right,val,lazy;
}NODE[maxn<<2];
int main(){
int t;
scanf("%d",&t);
while (t--) {
int n,m;
scanf("%d%d",&n,&m);
Max[0]=Max[1]=-INF;
for (int i=1; i<=n; i++) {
Csum[i]=0;
scanf("%d%d",&team[i],&B[i]);
}
for (int i=1; i<=m; i++) {
int idx;
scanf("%d",&idx);
Csum[idx]++;
}
for (int i=1; i<=n; i++) Csum[i]+=Csum[i-1];
int cnt=0;
for (int i=n; i>=1; i--) {
int sum=Max[team[i]^1];
if (sum<=B[i]-Csum[i-1]) cnt++;
Max[team[i]]=max(Max[team[i]],B[i]-Csum[i-1]);
}
printf("%d\n",cnt);
}
return 0;
}
对于队伍数量达到n的情况,我们核心思路还是维护这个式子,只不过不止两个变量维护最大值了,需要n个变量维护每个队伍的最大值,但是如果朴素维护,复杂度也会退化到 ,所以我们开一颗维护最大值的线段树即可,复杂度
,代码如下:
#include <cstring>
#include <iostream>
#include <stdio.h>
#include <algorithm>
#include <cmath>
#include <map>
#include<time.h>
#define ll long long
using namespace std;
const int maxn=2e5+10,INF=0x3f3f3f3f;
int B[maxn],Csum[maxn],team[maxn];
struct node {
int Left,Right,val,lazy;
}NODE[maxn<<2];
void build(int l, int r, int idx) {
NODE[idx].Left=l,NODE[idx].Right=r;
NODE[idx].lazy=-INF;
NODE[idx].val=-INF;
if (l==r) return;
int m=(l+r)>>1;
build(l,m,idx<<1);
build(m+1,r,idx<<1|1);
}
void PushUp(int idx) {
NODE[idx].val=max(NODE[idx<<1].val,NODE[idx<<1|1].val);
}
void PushDown(int idx) {
if (NODE[idx].lazy!=-INF) {
NODE[idx<<1].val=max(NODE[idx<<1].val,NODE[idx].lazy);
NODE[idx<<1].lazy=max(NODE[idx<<1].lazy,NODE[idx].lazy);
NODE[idx<<1|1].val=max(NODE[idx<<1|1].val,NODE[idx].lazy);
NODE[idx<<1|1].lazy=max(NODE[idx<<1|1].lazy,NODE[idx].lazy);
NODE[idx].lazy=-INF;
}
}
void Updata(int l, int r, int val, int idx) {
if (NODE[idx].Left==l&&NODE[idx].Right==r) {
NODE[idx].lazy=max(NODE[idx].lazy,val);
NODE[idx].val=max(NODE[idx].val,val);
return;
}
PushDown(idx);
int m=(NODE[idx].Left+NODE[idx].Right)>>1;
if (r<=m) Updata(l,r,val,idx<<1);
else if (l>m) Updata(l,r,val,idx<<1|1);
else {
Updata(l,m,val,idx<<1);
Updata(m+1,r,val,idx<<1|1);
}
PushUp(idx);
}
int query(int l, int r, int idx) {
if (l>r) return -INF;
if (NODE[idx].Left==l&&NODE[idx].Right==r) {
return NODE[idx].val;
}
PushDown(idx);
int m=(NODE[idx].Left+NODE[idx].Right)>>1;
int res;
if (r<=m) res=query(l,r,idx<<1);
else if (l>m) res=query(l,r,idx<<1|1);
else res=max(query(l,m,idx<<1),query(m+1,r,idx<<1|1));
PushUp(idx);
return res;
}
int main(){
int t;
scanf("%d",&t);
while (t--) {
int n,m;
scanf("%d%d",&n,&m);
build(1,n,1);
for (int i=1; i<=n; i++) {
Csum[i]=0;
scanf("%d%d",&team[i],&B[i]);
team[i]++;
}
for (int i=1; i<=m; i++) {
int idx;
scanf("%d",&idx);
Csum[idx]++;
}
for (int i=1; i<=n; i++) Csum[i]+=Csum[i-1];
int cnt=0;
for (int i=n; i>=1; i--) {
int Max=max(query(1,team[i]-1,1),query(team[i]+1,n,1));
if (Max<=B[i]-Csum[i-1]) cnt++;
Updata(team[i],team[i],B[i]-Csum[i-1],1);
}
printf("%d\n",cnt);
}
return 0;
}


京公网安备 11010502036488号