离线操作及应用

离线操作:读入所有的操作数据,然后一次性处理。
在线操作:每读入一个操作数据,就进行一次操作。
值得注意的是两者并不等价,有的时候,离线操作要比在线操作要快。
但是,离线操作的缺点也非常明显。那就是要占用一些额外的空间。
我们可以这样去理解。
我们的程序需要和输入端连线才能读取数据,如果我们一次性全部读完,我们就可以断开连线,然后操作,这就是离线操作。而如果我们每读入一个数据,就处理一次,那么我们后面肯定还有没读取的数据,所以我们不能断开连线,就要在线操作。
这样就可以很好地理解了

,当算法时间复杂度过高且没有办法优化时(一般是有很多询问需要大量重复计算),可以通过创建数组进行离线操作,将每一次操作的答案保存在数组当中,注意离散操作往往会伴随着数据的有序性,例如下题,就需要排序确保数据有序性,避免需要回退之类的操作。


例题:
P4185 [USACO18JAN]MooTube G - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)

相关系数(相关性 ):任意一对视频的相关性定义为沿此路径的任何连接的最小相关性

输入: 
有n个视频,m个询问
接下来有n-1行,每行表示视频p和视频q有相关性,且相关系数为r
接下来m行,每行一个询问,当相关系数为k时,与第v个视频相关性大于k的视频数 

输出:
每行一个整数表示视频数
 


  AC代码

#include<iostream>
#include<algorithm>

using namespace std;

const int maxn =  100007;

int pre[maxn],depth[maxn];
int ans[maxn];	//ans用来保存离线操作下的结果 

struct node		
{
	int l,r,dis;	//视频l和视频r的相关性为dis 
	node () {}
	node(int x,int y,int v) : l(x),r(y),dis(v) {}
}a[maxn*40];    //struct开大一点,一般乘40,不然会及怪的运行错误

struct kkk	
{
	int v,pot;		//v,pot对应每一次询问的相关性界值和视频号 
	int pos; 	//每一次询问的编号 
}b[maxn*40];

bool cmp1(node x,node y)
{
	return x.dis > y.dis; 
}

bool cmp2(kkk x,kkk y)
{
	return x.v > y.v;
}

int find(int x)
{
	if(pre[x] == x)
		return x;
	return pre[x] = find(pre[x]);
}

void unite(int x,int y)
{
	int fx = find(x);
	int fy = find(y);
	if(fx != fy)
	{
		pre[fx] = fy;
		depth[fy]+= depth[fx];
	}
}
int main()
{
	int n,m;
	
	//输入数据初始化 
	cin >> n >> m;	
	for(int i=1;i<=n;i++)
	{
		pre[i] = i;
		depth[i] = 1;		
	} 
	for(int i=1;i<n;i++)
		cin >> a[i].l >> a[i].r >> a[i].dis;
	for(int i=1;i<=m;i++)
	{
		cin >> b[i].v >> b[i].pot;
		b[i].pos = i;
	} 
	
	/*  对结构体排序,让每一次询问都从大到小询问,这样就可以避免先询问小的,后续询问大的,
	 *  导致前面已经联合的小的视频无法去除,也保证可以按照顺序联合将相关系数大于该询问的两个视频联合
	 * (联合视频的结构体已经按相关系数排序) 
	 *  从而避免了多次查找,但因为排序会打乱顺序,所以要对查找结构体添加编号pos, 
	*/
	sort(a+1,a+1+n,cmp1);
	sort(b+1,b+1+m,cmp2);
	
	//
//	cout << "测试" << endl; 
//	for(int i=1;i<n;i++)
//		cout << a[i].l << " " << a[i].r << " " << a[i].dis << endl;
//	for(int i=1;i<=m;i++)
//		cout << b[i].v << " " << b[i].pot << endl;
//	cout << "测试" << endl; 
	//
			
	//由相关系数从大到小便利每一次询问 
	int cut = 1;	//便利保存相关关系的结构体	!!这里只需要便利一次!! 
	for(int i=1;i<=m;i++)
	{
		int d = b[i].v;	//保存这次询问的相关性大小 
		int p = b[i].pot;	//保存这次询问的视频节点pot 
		int pos = b[i].pos;	//记录编号用于保存ans 
		while(a[cut].dis >= d && cut < n)
		{
			unite(a[cut].l,a[cut].r);
			cut++;	
		} 	
		ans[pos] = depth[find(p)] - 1; 
	}
	
	//输出
	for(int i=1;i<=m;i++)
		cout << ans[i] << endl; //深度要减一,减去自己 
	
	return 0;
} 

posted @ 2022-05-05 08:42  光風霽月  阅读(57)  评论(0编辑  收藏  举报