P9571 Horizon Blue 题解

发布时间 2023-08-19 19:18:37作者: tx_infinity

原题链接

题目大意:

\(有三个操作,分别为\)
\(操作1加入一条直线\)
\(操作2查询与一条直线相交但不重合的直线条数\)
\(操作3删除所有与一条直线相交或重合的直线\)
\(注意:后面两个操作的直线并不需要加入\)

\(显然,两条直线相交不重合,当且仅当其k值不同\)
\(所以可以把所有直线按k值分类,则第二个操作的查询答案显而易见,为直线总数减去k为给出k值相同的直线条数\)
\(然后看到第三个操作,需要删除与其k值不同的直线以及与其k,b都相同的直线\)
\(可以考虑对每一个k值开一个map用于储存当前k值下,每个b值有多少条直线\)
\(删除重合直线时即可直接删除\)
\(再看相交的情况,即k值不同,对于每个k只需将其map进行clear即可\)
\(最后还要用栈存储下所有存在且未被删除的k值,复杂度O(n log n)\)
注:\(k值可能有负数,所以需要加上一个很大的数使其变为正数\)

点击查看代码
#include<bits/stdc++.h>
using namespace std;
const int N=1e5+7;
int q[N],top;//栈,用于存储存在的k值,降低复杂度 
struct Node
{
	map<int,int>b;
	int cnt;//记录当前k值一共有多少条直线 
}a[N<<1];
int n,sum;//sum记录总共多少直线 
signed main()
{
	ios::sync_with_stdio(0);
	cin.tie(0);
	cout.tie(0);
	cin>>n;
	for(int i=1;i<=n;i++)
	{
		int opt,k,b;
		cin>>opt>>k>>b;
		k+=100000;
		if(opt==1)
		{
			if(a[k].cnt==0)
			q[++top]=k;//如果k没入栈,将其入栈 
			a[k].b[b]++; 
			a[k].cnt++;
			sum++;
		}
		else
		if(opt==2)
		{
			cout<<sum-a[k].cnt<<'\n';
		}
		else
		{
			while(top)
			{
				if(q[top]==k)
				{
					top--;
				}
				else
				{
					a[q[top]].cnt=0;
					a[q[top]].b.clear();//清空 
					top--;
				}
			}
			sum=a[k].cnt=a[k].cnt-a[k].b[b];
			a[k].b[b]=0;
			if(sum)
			q[++top]=k;//k不一定被清空了 ,可能要加回去 
		}
	}
	return 0;
}