ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

西瓜树之二

2021-10-30 10:37:08  阅读:176  来源: 互联网

标签:连通 西瓜 int wh le 编号 之二 getchar


题目描述

给定一棵 \(N\) 个节点的西瓜树,第 \(i\) 个点的编号为 \(i\),第\(j\)条边的编号为\(j\)。

有\(Q\)次查询,每次给出两个整数\(l,r\),查询如果只保留树上点编号在\([l,r]\)内的点,边编号在\([l,r]\)内的边,还剩下多少点连通块。

提示,给出 \(l,r\) 后,此时点 \(a\) 与 \(b\) 连通等价于 \(l\le a,b\le r\)且 \(a\) 到 \(b\) 在树上的简单路径中所有点与边编号都在 \([l,r]\) 之间。

\(N,Q\le 10^6\)

解法

一道树状数组的题,鬼知道这个华强专题的测试为什么那么喜欢考树(话说华强的西瓜为什么会长在树上,以及萨日朗到底是什么梗)。

询问之间互相独立且不带修改,考虑离线。

首先有一个结论就是,假如对于一堆树上的节点,每在它们任意两个之间连一条边,连通块就会减少一个,原因很简单。树的特性决定了任意一条边都只会连接两个不同的连通块(不然就会出现环,那就不是树了,毕竟西瓜树它也是树啊)。

于是做如下考虑:假如只保留点不保留边,那么会得到 \(r-l+1\) 个连通块;接下来考虑所有编号在\([l,r]\)中的边有多少条连接的两个点都是在 \([l,r]\) 的区间内。

可以给予每条边三个参数 \(id,x,y\) ,问题就转化成了有多少条边的三个参数都是在 \([l,r]\) 里的。进而把每条边的参数优化成 \(max,min\),问题就变成了有多少点的两个参数都是在 \([l,r]\) 内的,于是问题就转化成了平面上矩形内点数的问题。

树状数组离线处理即可。

#include<cstdio>
#include<algorithm>
//#define zczc
using namespace std;
const int N=1000010;
inline void read(int &wh){
    wh=0;int f=1;char w=getchar();
    while(w<'0'||w>'9'){if(w=='-')f=-1;w=getchar();}
    while(w<='9'&&w>='0'){wh=wh*10+w-'0';w=getchar(); }
    wh*=f;return;
}
inline int min(int s1,int s2){
	return s1<s2?s1:s2;
}
inline int max(int s1,int s2){
	return s1<s2?s2:s1;
}

int m,n,s[N],an[N];
namespace g{
	struct no{
		int x,y,pl;
		bool change,add;
	}b[N*6];
	inline bool cmp(no s1,no s2){
		if(s1.x==s2.x){
			if(s1.y==s2.y)return s1.change;
			else return s1.y<s2.y;
		}
		else return s1.x<s2.x;
	}
	int cnt;
	#define lowbit (wh&-wh)
	int t[N];
	void change(int wh){
		for(;wh<=m;wh+=lowbit)t[wh]++;
        return;
	}
	int work(int wh){
		int an=0;
		for(;wh;wh-=lowbit)an+=t[wh];
		return an;
	}
	#undef lowbit
	void add(int pl,int s1,int s2,bool change,bool add){
		cnt++;
		b[cnt].pl=pl;
		b[cnt].x=s1;
		b[cnt].y=s2;
		b[cnt].change=change;
		b[cnt].add=add;
		return;
	}
	void solve(){
		sort(b+1,b+cnt+1,cmp);
		for(int i=1;i<=cnt;i++){
			if(b[i].change){
				change(b[i].y);
				continue;
			}
			int now=work(b[i].y);
			an[b[i].pl]+=now*(b[i].add?1:-1);
		}
		return;
	}
}

signed main(){
	
	#ifdef zczc
	freopen("in.txt","r",stdin);
	#endif
	
	int s1,s2;
	read(m);read(n);
	for(int i=1;i<m;i++){
		read(s1);read(s2);
		g::add(0,min(min(s1,s2),i),max(max(s1,s2),i),true,false);
	}
	for(int i=1;i<=n;i++){
		read(s1);read(s2);
		s[i]=s2-s1+1;
		g::add(i,s2,s2,false,true);
		g::add(i,s1-1,s1-1,false,true);
		g::add(i,s1-1,s2,false,false);
		g::add(i,s2,s1-1,false,false);
	}
	g::solve();
	for(int i=1;i<=n;i++)printf("%d\n",s[i]-an[i]);
	
	return 0;
}

标签:连通,西瓜,int,wh,le,编号,之二,getchar
来源: https://www.cnblogs.com/dai-se-can-tian/p/15484413.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有