P9571 Horizon Blue 题解

原题

更好的阅读体验

题目给出了三个操作

  • 1 k b 代表小 C 绘制了一条解析式为 $ y=kx+b $ 的直线。
  • 2 k b 代表小 C 询问你直线 $ y=kx+b $ 与多少条被绘制的直线有恰好一个公共点。
  • 3 k b 代表小 C 擦除所有与直线 $ y=kx+b $ 有至少一个公共点的直线。

学过一次函数的都知道,两条直线如果 \(k\) 值不相等,那么这两条直线一定会相交且只有一个公共点。如果 \(k\) 值相等且 \(b\) 值不相等,那么这两条直线平行,如果 \(b\) 值相等,那么重合。

于是对于操作一,我们可以用一个数组累计 \(k\) 值相等的直线有多少条,并且累计 \(k,b\) 两值相等的直线有多少条(因为有可能存在重合,所以不光要累计 \(k\) 值相同的直线的数量,也要累计 \(k,b\) 两个值都相同,即相互重合的直线的数量)。顺便也要记录一下 \(k,b\) 两个值以及目前画板上存在的直线数量,后面操作要用到。

对于操作二,我们可以将操作一中存下来的画板上存在的直线数量减去当前 \(k\) 值的直线的数量,即 \(k\) 值与题目给的 \(k\) 值不同的直线数量,也就是题目要求的直线 $ y=kx+b $ 与多少条被绘制的直线有恰好一个公共点。

对于操作三,直接枚举前面操作一存下的不同的 \(k,b\) 值,然后判断 \(k\) 值是否相同,不同就抹去,相同就存回这个数组中,最后再抹去重合的直线。

然后这道题就轻松的解决了喏。

#include<bits/stdc++.h>
using namespace std;
const int N=2e5;
int n,obt,K,B,tmp,k[100005],b[100005],len[N+5],cnt;
map<pair<int,int>,int>c;
int main()
{
	scanf("%d",&n);
	while(n--)
	{
		scanf("%d%d%d",&obt,&K,&B);
		K+=100000;
		if(obt==1)
		{
			++c[{K,B}];//累计k,b两个值相等的直线有多少条
			++len[K];//累计k值相等的直线有多少条 
			if(c[{K,B}]==1)k[++cnt]=K,b[cnt]=B;//记录k,b两个值,方便后面操作三 
			++tmp;//记录画板上已有的直线数量 
		}
		else if(obt==2)printf("%d\n",tmp-len[K]);
		else
		{
			int sum=cnt;
			cnt=0;
			for(int i=1;i<=sum;++i)
			{
				if(k[i]!=K)len[k[i]]=0,c[{k[i],b[i]}]=0;//k值不同的直线就全部抹去 
				else k[++cnt]=k[i],b[cnt]=b[i];//k值相同就存回记录k,b值的数组
			}
			tmp=len[K];//画板上剩下的直线只有为k值的直线数量
			tmp-=c[{K,B}];//也要减去重合的直线,才是最后画板剩下的直线数量
			len[K]-=c[{K,B}];//k值直线数量也要减去重合的直线
			c[{K,B}]=0;//抹去重合的直线 
		}
	}
	return 0;
}
posted @ 2023-08-22 18:32  Thenyu  阅读(77)  评论(0)    收藏  举报