一道时间分治的题

Graph
输入文件:graph.in
输出文件:graph.out
时间限制:1 second
空间限制:512 MB
题目描述
现在你要维护一张无向的简单图。你要执行如下操作:
0:加入一条边。保证它不存在。
1:删除一条边。保证它存在。
2:查询两个点是否联通。
输入格式
输入的第一行是两个正整数n,m 。
接下来 行,每一行三个整数opt,x,y 。其中opt 表示操作编号。
输出格式
对于每一个opt = 2的询问,输出一行 Yes 或 No ,表示两个节点是否连通。
样例
样例输入
样例输出
4 10
0 1 2
0 2 3
0 3 1
2 1 4
0 4 3
2 1 4
1 2 3
2 1 4
1 1 3
2 1 4
样例输出
No
Yes
Yes
No
n <= 5000,m <= 2000000

这道题可以lct板子,可以过、、、但是比时间分治劣。(第二次写,然而第一次用lct...然后就忘了,,,,结果只打了个暴力-。-、)

一条边可以存活的时间为x,u;

那么以时间为下标建线段树。

把区间(x,u)加1;

只有线段树上一个结点所代表的区间被(x,u)全部包含才能把这条边加到这个结点上。

dfs每到一个结点把这个结点存的边添加(用栈来记录加了哪些边,用并查集处理,但注意不压缩路径,因为只改一个点的fa,如果压缩了改很多个点的fa.加一条边,改变一个点的所在集合大小,以及另一个点的fa...)

一直到叶子结点如果这个结点所代表的区间(即这个时间点有询问则处理)

如果没有就一直退栈,每到一个点把这个点所存的边,全部删除=、=(即把一个集合的大小改为原来的大小,把另一个点的fa改为原来的fa)

#include<bits/stdc++.h>
using namespace std;
int n, m, vis[2000005],bian[5005][5005], cnt, cx, ha[2000005],ans[2000005], c[2000005], shi[2000005], fa[5005], size[5005], huan[2000005], hui[2000005], cha[2000005], cha1[2000005];
vector<int>bi[2000005];
void read(int &x)
{
    x = 0;
    char c = getchar();
  while(c < '0' || c > '9')
  {
  	    c = getchar();
  }  
  while(c >= '0' &&c <= '9')
  {
     x = 10 * x + c - '0';
     c = getchar();
  } 
}
struct node
{
	int fa, x, y;
};
node zhan[2000000];
int find(int x)
{
	if(x == fa[x]) return x;
	return find(fa[x]);
}
void modify(int o, int l, int r, int ql, int qr, int val)
{
	if(ql <= l && r <= qr)
	{
		bi[o].push_back(val);
	    return ;
	}
	int mid = (l + r) >> 1;
	if(ql <= mid)  modify(2*o, l, mid, ql, qr, val);
	if(mid < qr) modify(2*o+1, mid+1, r, ql, qr,val);
}
void dfs(int o, int l, int r, int tp)
{
	int he = tp;
	int mx = bi[o].size();
	for(int i = 0; i < mx; i++)
	{
		int haha = bi[o][i];
		int r1 = find(huan[haha]);
		int r2 = find(hui[haha]);
	   if(r1 != r2)
	   {
	   	  if(size[r1] < size[r2])swap(r1,r2);
	   	  zhan[++tp].fa = fa[r2];
		  zhan[tp].x = r1;
		  zhan[tp].y = r2;
		  size[r1] += size[r2];
		  fa[r2] = r1;
	   }
	}
	if(l == r)
	{
		if(c[l] != 0)
		{
			int r1 = find(cha[c[l]]);
			int r2 = find(cha1[c[l]]);
			if(r1 == r2)
			{
				ans[c[l]] = 1;
			}
			else ans[c[l]] = 0;
		}
		for(int i = he +1; i <= tp; i++)
		{
			int x = zhan[i].x;
			int y = zhan[i].y;
			size[x] -= size[y];
			fa[y] = zhan[i].fa;
		}
		tp = he;
		return ;
    }
    int mid = (l + r) /2; 
    dfs(o*2, l, mid, tp );
    dfs(o*2+1, mid+1, r, tp );
    for(int i = he+1; i <= tp; i++)
		{
			int x = zhan[i].x;
			int y = zhan[i].y;
			size[x] -= size[y];
			fa[y] = zhan[i].fa;
		}
		tp = he;
}
int main()
{
	freopen("graph.in","r",stdin);
	freopen("graph.out","w",stdout);
	 read(n);
	read(m);
	for(int i = 1; i <= m; i++)
	{
		int a,b,d;
		read(a);
	 read(b);
		 read(d);
		if(a == 0)
		{
			++cnt;
			bian[b][d] = bian[d][b] = i;
		    ha[i] = cnt;
		    huan[cnt] = b;
		    hui[cnt] = d;
		   shi[cnt] = i;   
		}
		if(a == 1)
		{
			vis[ha[bian[b][d]]]= 1;
			modify(1, 1, m, bian[b][d], i, ha[bian[b][d]]);
		}
		if(a == 2)
		{
			c[i] = ++cx;
			cha[cx] = b;
			cha1[cx] = d;
		} 
	}
	for(int i = 1; i <= cnt; i++)
	if(vis[i] == 0) modify(1, 1, m, shi[i], m,i);
	for(int i = 1; i <= n; i++)
	 {
	 	fa[i] = i; size[i] = 1;
	 }
	dfs(1,1,m,0);
	for(int i = 1; i <= cx; i++)
	if(ans[i] == 1) printf( "Yes\n" );
	else printf("No\n");
	return 0;
 } 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值