uva1455 - Kingdom

任务统计

工作日刷题 ( 1 / 5 ) (1/5) (1/5)

链接

https://vjudge.net/problem/UVA-1455

题解

这题的横坐标完全没有什么用
把连线向 y y y轴投影可以得到一些线段,因为只有合并操作所以线段只会取并集,并查集维护一下连通性以及线段的上下端点,线段树维护每个点上线段的个数以及带权线段的权值和
这里可以标记永久化,因为是单点查询,所以可以简单地将从根节点到叶子节点这条路径上所有的标记求和

代码

#include <bits/stdc++.h>
#define maxn 1000010
using namespace std;
typedef long long ll;
struct segtree
{
	segtree *lch, *rch;
	ll l, r, add;
}pool[maxn<<3], *root1, *root2;
ll x[maxn], y[maxn], ndtot;
ll read(ll x=0)
{
	ll c, f=1;
	for(c=getchar();!isdigit(c);c=getchar())if(c=='-')f=-f;
	for(;isdigit(c);c=getchar())x=x*10+c-48;
	return f*x;
}
void segadd(segtree *p, ll l, ll r, ll v)
{
	ll mid(p->l+p->r>>1);
	if(l<=p->l and r>=p->r){p->add+=v;return;}
	if(l<=mid)segadd(p->lch,l,r,v);
	if(r>mid)segadd(p->rch,l,r,v);
}
ll getv(segtree *p, ll pos)
{
	ll mid(p->l+p->r>>1);
	if(p->l==p->r)return p->add;
	if(pos<=mid)return getv(p->lch,pos)+p->add;
	else return getv(p->rch,pos)+p->add;
}
void build(segtree *p, ll l, ll r)
{
	ll mid(l+r>>1);
	p->l=l, p->r=r;
	p->add=0;
	if(l==r)return;
	build(p->lch=pool+ ++ndtot,l,mid);
	build(p->rch=pool+ ++ndtot,mid+1,r);
}
struct UFSet
{
	ll f[maxn], up[maxn], down[maxn], size[maxn];
	ll find(ll x){return x==f[x]?x:f[x]=find(f[x]);}
	void merge(ll x, ll y)
	{
		auto fx=find(x), fy=find(y);
		if(size[fx]>size[fy])swap(x,y), swap(fx,fy);
		up[fy]=max(up[fy],up[fx]);
		down[fy]=min(down[fy],down[fx]);
		size[fy]+=size[fx];
		f[fx]=fy;
	}
	void init(ll n)
	{
		for(auto i=1;i<=n;i++)f[i]=i, size[i]=1, up[i]=down[i]=y[i];
	}
}ufs;
int main()
{
	ll T=read(), n, m, i;
	while(T--)
	{
        ndtot=0;
		n=read();
		for(i=1;i<=n;i++)x[i]=read(), y[i]=read();
		ufs.init(n);
		build(root1=pool+ ++ndtot,0,1000000);
		build(root2=pool+ ++ndtot,0,1000000);
		m=read();
		while(m--)
		{
			char s[10];
			scanf("%s",s);
			if(*s=='r')
			{
				auto a(read()+1), b(read()+1);
                ll x, y;
				if(ufs.find(a)!=ufs.find(b))
				{
					x=ufs.down[ufs.find(a)], y=ufs.up[ufs.find(a)];
					if(x<y)segadd(root1,x,y-1,-1), segadd(root2,x,y-1,-ufs.size[ufs.find(a)]);
					x=ufs.down[ufs.find(b)], y=ufs.up[ufs.find(b)];
					if(x<y)segadd(root1,x,y-1,-1), segadd(root2,x,y-1,-ufs.size[ufs.find(b)]);
					ufs.merge(a,b);
					x=ufs.down[ufs.find(a)], y=ufs.up[ufs.find(a)];
					if(x<y)segadd(root1,x,y-1,1), segadd(root2,x,y-1,ufs.size[ufs.find(a)]);
				}
			}
			else
			{
				auto y(read()), _(read());
				printf("%lld %lld\n",getv(root1,y),getv(root2,y));
			}
		}
	}
	return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值