Teach you how to divide the tree

Point

•Look at a question first

• P3806 Given a tree with n points, ask whether a point pair with a distance of k exists on the tree.
•N<=10000

• Believe that you are smart! n dfs times!

• But can’t make it

Then let's see how to do it

• What is point divide and conquer?

• Point divide and conquer is an efficient way to deal with problems on the tree, with excellent time complexity and clever thinking.

•First we introduce the center of gravity of the tree

• The center of gravity of the tree is also called the center of mass of the tree. Find a point where the largest subtree has the least number of nodes in all subtrees, then this point is the center of gravity of the tree. After deleting the center of gravity, the generated multiple trees are as balanced as possible.

•What does that mean?

• We can deduce from here that the size of any subtree rooted at the center of gravity of the tree does not exceed n/2

• How to ask for it?

• Just define dfs directly

• Look at the code

Insert picture description here
• We just need to keep looking for the center of gravity and use these centers to calculate the answer we want

• Let’s give an example

•First we can find a center of gravity and calculate the contribution of all paths through the center of gravity to the answer

•Usually traverse the subtree to solve

• This question asks whether there is a path of length k, which is the length recorded to each point of the subtree with the center of gravity as the starting point

• If you can use a bucket, do it directly, if you can’t, use a map mapm a p finds a length from the center of gravity toxxThe point of x is to see if the length from the center of gravity isk − x kxkx sub points within the two points can not focus attention again to the same tree son

• The path contribution through this center of gravity is counted

• Then the center of gravity divided the original tree into multiple sub-trees

• Divide and conquer to calculate the contribution of the subtree

•Similarly find the subtree's center of gravity statistics contribution and divide and conquer...and so on

• Because we can deduce from here that the size of any subtree rooted at the center of gravity of the tree does not exceed n/2

• Each time the size of the tree will not exceed half of the original, log 2 log_2log2After N times, the size of the tree will become 1, and each time the entire tree can be traversed at most O (N) O (N)O ( N ) , the complexity isO (N log N) O (NlogN)O ( N L O G N ) of

Dotted tree

• The dotted tree is based on dot divide and conquer, the original tree is "turned into virtual" structure.

• In the process of point divide and conquer, we store the superior center of gravity of each divide and conquer, which is the parent-child relationship of the dotted tree.

• Obviously, according to the principle of point divide and conquer, the tree height of the point branch tree is logn lognl o g n . In this way, we can use this tree to run something like "From the point of inquiry, keep jumpingfa faThe violence of f a , to solve the multiple inquiries/modifications on some trees.

Take a tree to simulate building a branch tree

Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
Insert picture description here
• Look at the question

• P6329 gives a tree with point weights and requires online processing.
• The sum of the point weights of points whose distance between 0 xk and node x is less than or equal to k
• 1 xy The point weight of node x becomes y
1 ≤ n, m ≤ 1 0 5 1≤n,m≤10^51n,m105

• Build a point-by-tree, each point maintains a vector as a bucket, and maintains the point weight sum of the distance k from the current point in the subtree on the point-by-tree. That is, the vector subscript is k, and the value is the sum of weights. Every time you ask for a vector, dfs traverses the subtree

• The answer to the subtree is to find the prefix sum of the vector.

•In this way, for the query, you only need to jump to the branch tree each time, and then calculate the distance fa fa for each fa on the branch treef ak - dis (fa, x) k-dis (fa, x)kd i s ( f a ,The contribution of x ) is just fine. (Fa faf axxxdis (fa, x) dis (fa, x)d i s ( f a ,x ) is so far away, so the point that can contribute is away fromfa faf ak - dis (fa, x) k-dis (fa, x)kd i s ( f a ,x ) far)

• But there is another problem, that is, for the current fa faThose subtrees with f a as the root are counting the nextfa faWhen f a , it will be weighted.

• So we have to maintain a bucket, which means xxx point within the molecular tree, to the point branchxxThe distance of x 's father iskkThe point weight of k . Since the side weights are all 1, this operation will be very convenient.

•Considering that if there is a modification , it is nothing more than replacing the bucket with a tree array .

• When building a tree, each point has at most logn lognl o g n ancestors so the most visitedlogn lognl o g n times

• For this problem, because the tree array is used, there is one more log

• Time to build a tree O (nlog 2 n) O(nlog^2 n)O ( n l o g2 n)

• How to modify it?

• Suppose we modify the point as x

• Every time the violence jumps, every ancestor on the tree fa

• Modified the contribution of x to fa

• So logn logn must be skipped for every modificationl o g n Sub-ancestor modification contribution requiresO (logn) O(logn)O ( l o g n )

• Modification time O (log 2 n) O(log^2 n)O(log2 n)

• Then when solving the answer, also jump logn lognl o g n second ancestor

O (logn) O(logn) is required for each contribution in the subtreeO ( l o g n )

•The time to solve the answer O (log 2 n) O(log^2 n)O(log2 n)

Look at another question

P2056 [ZJOI2007] Hide and seek

Jiajia and Wind are a loving couple, and they have many children. One day, Jiajia, Wind and the children decided to play hide and seek at home. Their home is very large and has a peculiar structure. It consists of N rooms and N −1 two-way corridors. The distribution of these N−1 corridors makes any two rooms reachable to each other.

The game is like this, the children are in charge of hiding, Jiajia is in charge of finding, and Wind is in charge of manipulating the lights in these N houses. At the beginning, all the lights were not turned on. Every time, the children will only hide in the room where the lights are not turned on, but in order to increase the excitement, the children will ask to turn on the light in a certain room or turn off the light in a certain room. In order to evaluate the complexity of a certain game, Jiajia wants to know the distance between the two farthest possible children (that is, the distance between the two farthest rooms with lights off).

We will define each operation in the following form:

-C(hange) i changes the lighting state of the i- th room, if it was turned on, it will be turned off; if it was turned off, it will be turned on.
-G(ame) Start a game and query the distance between the two furthest rooms with lights off.

Obviously build a branch tree

Every time we switch a light, it will affect the information of a chain on the dotted tree. Just jump directly.

Consider maintaining answers, we open three big root piles , one to maintain the longest chain in the subtree, one to maintain the longest chain to the parent node, and one to maintain all the answers.

Maintain a heap of all answers, pay attention to update at any time

When counting answers, each subtree only needs to take the largest value and the next largest value .

The overall complexity is O (nlog 2 n) O(nlog_2n)O ( n l o g2n ) , enough to pass this question.

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#pragma GCC optimize(3)
#pragma GCC optimize(fast)
#define inf 1e9
#define N 100100
using namespace std;
inline char get_char(){
	static char buf[1000000],*p1,*p2;
    return p1==p2&&(p2=(p1=buf)+fread(buf,1,1000000,stdin),p1==p2)?EOF:*p1++;
}
inline int read(){
    int numm=0;
    char _;_=get_char();
    while(_<'0'||_>'9'){_=get_char();} 
    while(_>='0'&&_<='9'){numm=(numm<<3)+(numm<<1)+(_^48);_=get_char();   }
    return numm;
}
int n,f1[N],nxt1[N*2],data1[N*2],num,now,siz[N];
int f[N],nxt[N*2],data[N*2],dep[N];
int fa[N],dis[N];
bool vis[N],lt[N];
vector<int> disnow[N];
struct node{
	priority_queue<int> x,y;
	inline void push(int a){x.push(a);}
    inline void del(int a){y.push(a);}
    inline int top(){while(y.size()&&x.top()==y.top())x.pop(),y.pop();return x.top();}
    inline int size(){return x.size()-y.size();}
    inline void pop(){while(y.size()&&x.top()==y.top())x.pop(),y.pop();x.pop();}
    inline int sectop(){int a=top();pop();int b=top();push(a);return b;} 
	inline void clear(){while(x.size())x.pop();while(y.size())y.pop();}
}ans,far[N],ma[N];
inline void ans_push(node &x){
	if(x.size()>=2)ans.push(x.top()+x.sectop());
}
inline void ans_del(node &x){
	if(x.size()>=2)ans.del(x.top()+x.sectop());
}
void add(int x,int y){
	nxt1[++num]=f1[x];
	f1[x]=num;
	data1[num]=y;
}
void add2(int x,int y){
	nxt[++num]=f[x];
	f[x]=num;
	data[num]=y;
}
void find_rt(int x,int &root,int sum,int pp){
	siz[x]=1;
	int y,maxx=0;
	for(int i=f1[x];i;i=nxt1[i]){
		y=data1[i];
		if(y==pp||vis[y])continue;
		find_rt(y,root,sum,x);
		siz[x]+=siz[y];
		maxx=max(maxx,siz[y]);
	}
	maxx=max(siz[x],sum-siz[x]);
	if(maxx<now){
		now=maxx;root=x;
	}
}
void get_far(int s,int x,int y,int pp){
	far[0].push(y);
	disnow[x].push_back(y);
	siz[x]=1;
	int v;
	for(int i=f1[x];i;i=nxt1[i]){
		v=data1[i];
		if(v==pp||vis[v])continue;
		get_far(s,v,y+1,x);
		siz[x]+=siz[v];
	}
}
void build(int x,int pp){
	vis[x]=1;
	int y,root;
	for(int i=f1[x];i;i=nxt1[i]){
		y=data1[i];
		if(vis[y])continue;
		far[0].clear();
		get_far(pp,y,1,x);
		now=inf;
		find_rt(y,root,siz[y],-1);
		far[root]=far[0];fa[root]=x;dep[root]=dep[x]+1;
		add2(x,root);
		if(far[root].size())ma[x].push(far[root].top());
		build(root,x);
	}
	ma[x].push(0);
	ans_push(ma[x]); 
}

void work1(int x){
	int xx=x,pp,tmp=1;
	ans_del(ma[x]);
	ma[x].del(0);
	
	while(fa[xx]){
		pp=fa[xx];
		ans_del(ma[pp]);
		ma[pp].del(far[xx].top());
		xx=pp;
	}
	xx=x;
	ans_push(ma[x]);
	
	while(fa[xx]){
		pp=fa[xx];
		tmp=disnow[x][dep[pp]];
		far[xx].del(tmp);
		if(far[xx].size())
		ma[pp].push(far[xx].top());
		ans_push(ma[pp]);
		xx=pp;
	}
}

void work2(int x){
	int xx=x,pp,tmp=1;
	
	ans_del(ma[x]);
	while(fa[xx]){
		pp=fa[xx];
		ans_del(ma[pp]);
		if(far[xx].size())
		ma[pp].del(far[xx].top());
		xx=pp;
	}
	xx=x;
	ma[x].push(0);
	ans_push(ma[x]);
	while(fa[xx]){
		pp=fa[xx];
		tmp=disnow[x][dep[pp]];
		far[xx].push(tmp);
		ma[pp].push(far[xx].top());
		ans_push(ma[pp]);
		xx=pp;
	}
}

int main(){
//	freopen("test.txt","r",stdin);
	n=read();
	
	int a,b;
	for(int i=1;i<n;i++){
		a=read();b=read();
		add(a,b);add(b,a);
	}
	num=0;
	int root;
	now=inf;
	find_rt(1,root,n,-1);
	build(root,-1);
	int Q; char ss='0';
	Q=read();
	while(Q--){
		ss=get_char();
		while(ss!='G'&&ss!='C')ss=get_char();
//		cout<<ss<<' ';
		if(ss=='G'){
			if(ans.size()) printf("%d\n",ans.top());
			else printf("-1\n"); 
		}
		else{
			a=read();
//			cout<<a<<endl;
			if(!lt[a]){
				work1(a);
			}
			else work2(a);
			lt[a]^=1;
		}
	}
} 

Originally speaking, I started to blog frequently in
July . Hey, it’s July 20th, why am I such a dish?

Guess you like

Origin blog.csdn.net/RA100FDM/article/details/107460101