2021 Niuke multi school 7 f. xay love trees (Chairman tree + DFS sequence)

Posted by Confusion101 on Sat, 25 Dec 2021 14:05:25 +0100

Question meaning: for a tree with two n points, find the largest subset and meet the following conditions:

  1. The point set is a continuous chain on tree 1
  2. The points are set on tree 2 without any ancestral relationship

Idea:

For condition 2:

If point u is the ancestor of point v, then the subtree of u must contain V, that is, it must contain the subtree of v. the problem involving the subtree can consider the dfs order.

dfs order property: dfs order can divide each subtree into several intervals [l, r], and there are only two cases for the divided intervals: one interval completely contains another interval, and the two intervals do not intersect.

The problem is that the range of points in the set does not intersect and forms a chain in tree 1. If the range does not intersect, it can be judged by line segment tree or set.

For condition 1:

The initial idea is: in dfs, each point is added in turn to maintain the interval and judge whether there is an intersection with the current point set. However, the chain of tree 1 will be broken from the middle. If it is illegal, you need to backtrack and delete some points in the set until there is no intersection at the midpoint of the set. Write the chairman tree so that you can directly get the segment tree of any chain.

When ABCDEF to G is illegal, it will be gradually deleted from A until A legal chain head is found. (this can be blocked by long chain + chrysanthemum) n 2 n^2 n2, so you can change violence into dichotomy and find the legal chain head. The complexity is the worst n of stability l o g 2 n log^2n log2n)

Tips: because the chairman tree is used to maintain the interval and, and the interval is modified with the lazy flag, it can not be passed down like the ordinary pushdown to update the subtree, because the later version changes the state of the original tree when passing the lazy flag down (tormented me for a long time...).

Solution: mark it permanently. When looking for an interval, ensure that the updated interval must be the interval you want to find (write three in recursion). Then update all the way down, and all the intervals containing [l, r] are new nodes. Template questions hdu4348.

Then there is a more beautiful solution: sliding window on the tree. The essence is that the answer is monotonous, so the window size only increases without decreasing. Fallback is also a fallback window. Each point only goes in and out once at most. With the upper line segment tree, it is the complexity of nlogn, but the constant is a little large.

My code:

#include<bits/stdc++.h>
using namespace std;
#define ll long long int
const int MAXN = 3e5 + 10;
const int N = 3e5 +10;
const int MAXM = 1e6 + 10;
const int INF=0x3f3f3f3f;
const ll LINF=0x3f3f3f3f3f3f3f3f;
const int NINF=-INF-1;
const ll mod=1e9+7;
#define PI acos(-1.0)
int T,n,first[MAXN],last[MAXN],top;
int sz[MAXN];
vector<int> e1[MAXN],e2[MAXN];
void getdfn(int u,int fa)
{
	++top;
	first[u]=top;
	sz[u]=1;
	for(auto it:e2[u])
	{
		if(it==fa) continue;
		getdfn(it,u);
		sz[u]+=sz[it];
	}
	return ;
};

int idx,root[MAXN],tim; 
struct node{
	int lc,rc;
	int sum,lz;
}tr[40*N];


int build(int l,int r)
{
	int p=++idx;


	tr[p].sum=tr[p].lz=0;
	if(l==r) 
	{	
		return p;	
	}

	int mid=l+r>>1;
	tr[p].lc=build(l,mid),tr[p].rc=build(mid+1,r);
	tr[p].sum=tr[tr[p].lc].sum+tr[tr[p].rc].sum;
	return p;
}

int update(int p,int l,int r,int x,int y,int val)
{	int q=++idx;
	tr[q]=tr[p];
	tr[q].sum=tr[p].sum+val*(y-x+1);
	if(x==l&&y==r)
	{
		tr[q].lz+=val;
		return q;
	}
	int mid=l+r>>1;
	if(x>mid) tr[q].rc=update(tr[p].rc,mid+1,r,x,y,val);
	else if(y<=mid) tr[q].lc=update(tr[p].lc,l,mid,x,y,val);
	else{
		
	tr[q].lc=update(tr[p].lc,l,mid,x,mid,val);
	tr[q].rc=update(tr[p].rc,mid+1,r,mid+1,y,val);
	}
	return q;
	
}
int query(int p,int q,int l,int r,int x,int y)
{	
	if(x<=l&&r<=y)
	{
		return tr[q].sum-tr[p].sum;
	}
	int ans=(tr[q].lz-tr[p].lz)*(y-x+1);
	int mid=l+r>>1;
	if(x>mid) ans+=query(tr[p].rc,tr[q].rc,mid+1,r,x,y);
	else if(y<=mid) ans+=query(tr[p].lc,tr[q].lc,l,mid,x,y);
	else{
	ans+=query(tr[p].lc,tr[q].lc,l,mid,x,mid);
	ans+=query(tr[p].rc,tr[q].rc,mid+1,r,mid+1,y);
	}
	return ans;
	
}
int ans;
void dfs(int u,int fa,int pre,int res)
{	ans=max(ans,res);
	
	for(auto it:e1[u])
	{	if(it==fa) continue;
		int l=first[it],r=first[it]+sz[it]-1;
		int x=query(root[pre],root[tim],1,n,l,r);
		

		if(x>0)
		{	int cnt=pre;
			while(query(root[cnt],root[tim],1,n,l,r)>0)
			{
				cnt++;
			}
			++tim;
			root[tim]=update(root[tim-1],1,n,l,r,1);

			int cha=cnt-pre;
			dfs(it,u,cnt,res-cha+1);
			tim--;
		}
		else{
			++tim;
			root[tim]=update(root[tim-1],1,n,l,r,1);
		
			dfs(it,u,pre,res+1);
			tim--;
			
		}
		
	}
	return;
	
}


int main()
{ 	
	scanf("%d",&T);
	while(T--)
{
	scanf("%d",&n);
	for(int i=1;i<=n;i++)
	e1[i].clear(),e2[i].clear(),sz[i]=0;
	
	for(int i=0;i<n-1;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		e1[a].push_back(b);
		e1[b].push_back(a);
	}
		for(int i=0;i<n-1;i++)
	{
		int a,b;
		scanf("%d%d",&a,&b);
		e2[a].push_back(b);
		e2[b].push_back(a);
	}
	top=0;
	getdfn(1,-1);

	idx=tim=0;
	root[0]=build(1,n);

	
	ans=1;
	tim++;
	root[1]=update(root[0],1,n,first[1],first[1]+sz[1]-1,1);
	
	
	dfs(1,-1,0,1);
	
	cout<<ans<<endl;

	
}


    return 0;
}

hdu4348

#include<bits/stdc++.h>
using namespace std;
#define int long long 
const int MAXN = 1e5 + 10;
const int MAXM = 1e6 + 10;
const int INF=0x3f3f3f3f;
const int LINF=0x3f3f3f3f3f3f3f3f;
const int NINF=-INF-1;
const int mod=1e9+7;
#define PI acos(-1.0)
int a[MAXN],n,q;
int root[MAXN],idx;
struct node{
	int lc,rc;
	int sum,lz;
}tr[MAXN*30];
int build(int l,int r)
{	
	int p=++idx;
	tr[p].sum=tr[p].lz=0;
	if(l==r)
	{	tr[p].sum=a[l];
		return p;	
	}
	 
	int mid=l+r>>1;
	tr[p].lc=build(l,mid),tr[p].rc=build(mid+1,r);
	tr[p].sum=tr[tr[p].lc].sum+tr[tr[p].rc].sum;
	return p;
}

int update(int p,int l,int r,int x,int y,int val)
{	int q=++idx;
	tr[q]=tr[p];
	tr[q].sum=tr[p].sum+val*(y-x+1);
	if(x==l&&y==r)
	{
		tr[q].lz+=val;
		return q;
	}
	int mid=l+r>>1;
	if(x>mid) tr[q].rc=update(tr[p].rc,mid+1,r,x,y,val);
	else if(y<=mid) tr[q].lc=update(tr[p].lc,l,mid,x,y,val);
	else{
		
	tr[q].lc=update(tr[p].lc,l,mid,x,mid,val);
	tr[q].rc=update(tr[p].rc,mid+1,r,mid+1,y,val);
	}
	return q;
	
}
int query(int p,int l,int r,int x,int y)
{	
	if(x<=l&&r<=y)
	{
		return tr[p].sum;
	}
	int ans=tr[p].lz*(y-x+1);
	int mid=l+r>>1;
	if(x>mid) ans+=query(tr[p].rc,mid+1,r,x,y);
	else if(y<=mid) ans+=query(tr[p].lc,l,mid,x,y);
	else{
	ans+=query(tr[p].lc,l,mid,x,mid);
	ans+=query(tr[p].rc,mid+1,r,mid+1,y);
	}
	return ans;
	
}
signed main()
{ 
	while(scanf("%lld%lld",&n,&q)==2)
	{
		
		for(int i=1;i<=n;i++)
		scanf("%lld",&a[i]);
		idx=0;
		root[0]=build(1,n);
	
		int time=0;
		char s[15];
		while(q--)
		{	int l,r;
			scanf("%s",s);
			if(s[0]=='Q')
			{
				scanf("%lld%lld",&l,&r);
				printf("%lld\n",query(root[time],1,n,l,r));
			}
			else if(s[0]=='C')
			{
				int val;
				scanf("%lld%lld%lld",&l,&r,&val);
				++time;
				root[time]=update(root[time-1],1,n,l,r,val);
				
			}
			
			else if(s[0]=='H')
			{
				int t;
				scanf("%lld%lld%lld",&l,&r,&t);
				printf("%lld\n",query(root[t],1,n,l,r));	
			}
			else{
				scanf("%lld",&time);
				idx=root[time+1];
			}
		}
		
			
	}

    return 0;
}

Topics: Algorithm data structure