Niuke-Red Blueprint (Chairman tree built on the dfs sequence of Kruskal's reconstruction tree)

Topic link: click to view

The main idea of ​​the topic: Given an undirected graph composed of n points and m edges, each edge has an edge weight and color, and the colors are divided into red and blue. Now there are q independent operations, each operation Will ask (x, t ), after deleting the red edge with ownership value greater than t and the blue edge with ownership value less than t, what is the size of the connected block where x is located

Note that for two points to be connected, there must be both a red reachable path and a blue reachable path.

Problem analysis: If you remove the restriction of the blue edge, only consider "after deleting the edge with a weight greater than t, what is the size of the connected block where the point x is located", this is the dfs of a standard Kruskal reconstruction tree For the order problem, there is no need to build a link segment tree, just output R[ x]-L[ x] + 1 directly to be the answer (the subtree interval represented by the dfs order)

Now that there is the restriction of the blue edge, it is not difficult to think of considering the red edge and the blue edge separately, so that every time you ask, suppose that the dfs order of the corresponding subtree of the point x in the red edge is [l1, r1 ], in The dfs order of the corresponding subtree in the blue edge is [l2, r2 ], and now our problem is converted to the size of the intersection of these two intervals corresponding to points 1 ~ n

Because the dfs order on the tree has a one-to-one correspondence with the nodes on the tree, in other words, the dfs order of the leaf nodes on the Kruskal reconstruction tree is also one-to-one with points 1 ~ n, thus forming a one-to-one relationship. Correspondence: the dfs order on the blue tree <=> point 1 ~ n <=> the dfs order on the red tree, through the transition from 1 to n, it is not difficult to see the dfs order on the blue tree and the red tree There is a one-to-one correspondence between n points in the dfs sequence, just use the chairman tree to map them

Code:
 

//#pragma GCC optimize(2)
//#pragma GCC optimize("Ofast","inline","-ffast-math")
//#pragma GCC target("avx,sse2,sse3,sse4,mmx")
#include<iostream>
#include<cstdio>
#include<string>
#include<ctime>
#include<cmath>
#include<cstring>
#include<algorithm>
#include<stack>
#include<climits>
#include<queue>
#include<map>
#include<set>
#include<sstream>
#include<cassert>
#include<bitset>
#include<unordered_map>
using namespace std;
     
typedef long long LL;
     
typedef unsigned long long ull;
     
const int inf=0x3f3f3f3f;

const int N=1e6+100;

struct Ex_Kruskal
{
	struct Edge
	{
		int x,y,w;
		bool operator<(const Edge& t)const
		{
			return w<t.w;
		}
	}edge[N];
	int f[N],L[N],R[N],val[N],dp[N][25],id[N],tot,index,cnt,n;
	vector<int>node[N];
	void init(int n)
	{
		cnt=tot=0;
		index=n;
		for(int i=0;i<=n<<1;i++)
		{
			f[i]=i;
			node[i].clear();
		}
	}
	int find(int x)
	{
		return f[x]==x?x:f[x]=find(f[x]);
	}
	void addedge(int x,int y,int w)
	{
		edge[++cnt]={x,y,w};
	}
	void solve()
	{
		sort(edge+1,edge+1+cnt);
		for(int i=1;i<=cnt;i++)
		{
			int xx=find(edge[i].x),yy=find(edge[i].y);
			if(xx!=yy)
			{
				f[xx]=f[yy]=++index;
				node[index].push_back(xx);
				node[index].push_back(yy);
				val[index]=edge[i].w;
			}
		}
		n=index;
		for(int i=1;i<=n;i++)
			if(find(i)==i)
				dfs(i,0);
	}
	int get_pos(int x,int limit)
	{
		for(int i=20;i>=0;i--)
			if(dp[x][i]&&val[dp[x][i]]<=limit)
				x=dp[x][i];
		return x;
	}
	void dfs(int u,int fa)
	{
		L[u]=++tot;
		id[tot]=u;
		dp[u][0]=fa;
		for(int i=1;i<=20;i++)
			dp[u][i]=dp[dp[u][i-1]][i-1];
		for(auto v:node[u])
			dfs(v,u);
		R[u]=tot;
	}
}t1,t2;

struct Node
{
	int l,r;
	int sum;
}tree[N*20];

int cnt,root[N];

void update(int num,int &k,int l,int r)
{
	tree[cnt++]=tree[k];
	k=cnt-1;
	tree[k].sum++;
	if(l==r)
		return;
	int mid=l+r>>1;
	if(num<=mid)
		update(num,tree[k].l,l,mid);
	else
		update(num,tree[k].r,mid+1,r);
}

int query(int i,int j,int l,int r,int L,int R)//[l,r]:目标区间 [L,R]:当前区间 
{
	if(L>r||R<l)
		return 0;
	if(L>=l&&R<=r)
		return tree[j].sum-tree[i].sum;
	int mid=L+R>>1;
	return query(tree[i].l,tree[j].l,l,r,L,mid)+query(tree[i].r,tree[j].r,l,r,mid+1,R);
}

void init()
{
	root[0]=0;
	tree[0].l=tree[0].r=tree[0].sum=0;
	cnt=1;
}

int main()
{
#ifndef ONLINE_JUDGE
//  freopen("data.in.txt","r",stdin);
//  freopen("data.out.txt","w",stdout);
#endif
//  ios::sync_with_stdio(false);
	init();
	int n,m,q;
	scanf("%d%d%d",&n,&m,&q);
	t1.init(n),t2.init(n);
	for(int i=1;i<=m;i++)
	{
		int x,y,c;
		scanf("%d%d%d",&x,&y,&c);
		x++,y++;
		if(c==0)//red
			t1.addedge(x,y,i);
		else//blue
			t2.addedge(x,y,-i);
	}
	t1.solve(),t2.solve();
	for(int i=1;i<=t2.n;i++)//遍历blue_tree的dfs序 
	{
		root[i]=root[i-1];
		if(t2.id[i]<=n)//i是t2的dfs序,t2.id[i]是在dfs序上对应的节点,t1.L[t2.id[i]]是对应在t1上的dfs序 
			update(t1.L[t2.id[i]],root[i],1,t1.n);
	}
	while(q--)
	{
		int x,t;
		scanf("%d%d",&x,&t);
		x++;
		int pos1=t1.get_pos(x,t),pos2=t2.get_pos(x,-t);
		int l1=t1.L[pos1],r1=t1.R[pos1];//对应在t1上的dfs序范围 
		int l2=t2.L[pos2],r2=t2.R[pos2];//对应在t2上的dfs序范围
		printf("%d\n",query(root[l2-1],root[r2],l1,r1,1,t1.n));
	}























    return 0;
}

 

Guess you like

Origin blog.csdn.net/qq_45458915/article/details/109113130