题解 P9343 【一曲新词酒一杯】
题目描述
这道题要求我们通过
解题思路
相对法与线段树
我们不难发现,这道题如果用暴力模拟,复杂度来到了我们难以接受的
我们容易得出,以相对的视角去看待操作
再次观察,可以发现其实所要求贴的红纸至少所需的数量也随之更新了,也是减去了
至此,我们便可以请出今天的主角了:线段树
这个数据结构可以以
完结撒花~
献上蒟蒻的 AC 代码:
#include <bits/stdc++.h>
using namespace std;
const int N=2000010;
int k,n,m,key,x;
bool flag;//输出判定,我个人的用法
struct node//经典区间线段树
{
int l,r;
int dat;
}t[N*4];
void build(int p,int l,int r)//建树
{
t[p].l=l,t[p].r=r;
if(l==r)
{
t[p].dat=0;
return;
}
int mid=(l+r)/2;
build(p*2,l,mid);
build(p*2+1,mid+1,r);
t[p].dat=min(t[p*2].dat,t[p*2+1].dat);
}
void change(int p,int x,int v)//单点更改
{
if(t[p].l==t[p].r)
{
t[p].dat+=v;
return;
}
int mid=(t[p].l+t[p].r)/2;
if(x<=mid) change(p*2,x,v);
else change(p*2+1,x,v);
t[p].dat=min(t[p*2].dat,t[p*2+1].dat);
}
int main()
{
scanf("%d",&k);
while(k--)
{
scanf("%d %d",&n,&m);
build(1,1,n);
flag=false;
int line=1;//至少数量为1,即最小值必须大于等于这个数
for(int i=1;i<=m;i++)
{
scanf("%d %d",&key,&x);
if(flag) continue;
flag=true;
switch(key)
{
case 1:
change(1,x,1);//自己加1
if(t[1].dat<line) flag=false;
break;
case 2:
change(1,x,-1);line--;//自己和至少所需数量减1
if(t[1].dat<line) flag=false;
break;
}
if(flag) printf("%d\n",i);
}
if(!flag) printf("-1\n");
}
return 0;
}
//我自己是用t[1]直接查询1-n最值的,没有写区间查询函数。想了解的OIer可以自行查阅相关资料。