SY's decryption game (line segment tree + scan line)

Brief description of title

One day, SY finally got Lua \rm LuaL u a 's U disk!

He saw that there was a compressed package called "Gentleman" in it, and he opened it without hesitation, and found that the compressed package had a password. SY could only see hundreds of thousands of folders in it, but not a single file, only the root directory. The next txt. SY is ecstatic, because even Lua \rm LuaL U A a txt are treasures! He clicked to read it, and it turned out to be dumbfounding. It was a question, but it gave a clue to the password:

  • There are NN in the compressed packageN folders, the containment relationship between each other forms a tree, the root is not important. Each folder has a number at the beginning, which indicates the main color number in the folder.
  • Find the number of paths without nodes of the same color, (u, v) (u,v)( u ,v )(v, u) (v, u)( v ,u ) is regarded as a path,(u, u) (u,u)( u ,u ) is also a legal path.
  • No more than 20 folders of the same color .
  • N ≤ 1 e 5    ,    1 ≤ C o l o r i ≤ N N\leq 1e5\;,\;1\leq Color_i\leq N N1e5,1ColoriN.

The final answer is the password of the compressed package! There is a problem with the SY compiler, so I have to ask you to help make this decryption game.

answer

This conversion is so wonderful, it must be written down:

Consider this question:


Given a tree of N points, given M sets of restrictions, each restriction is in the form of "ai and bi cannot appear on the path at the same time", and ask how many legal paths there are.


If a path (u, v) is illegal due to the restriction of the i-th group, it means that two points ai and bi appear on the path (u, v) at the same time.


If ai is the ancestor of bi, let p be the point on the path from ai to bi that is at a distance of 1 from ai. At this time, there are two points u and v, one of which is not in the subtree of p, and the other is in the subtree of bi.


If neither ai nor bi is an ancestor of another, then two points u and v, one is in the subtree of ai and the other is in the subtree of bi.


If a path (u, v) is mapped to a point on a two-dimensional plane, the abscissa is the DFS order of u, and the ordinate is the DFS order of v, then a set of restrictions allows one (no one) on the plane All the paths in the rectangles are invalid.) or two (when ai is the ancestor of bi).


At this time, the question is transformed into: There is an N × N two-dimensional plane with O(M) rectangles on it. Ask how many grids there are, which are not inside any rectangle. This problem can be solved with line segment tree + scan line in O(M log N) time complexity.


Well, back to this topic. It is required that the colors of the points on the path are different from each other, so pairs of points of the same color cannot appear on the path at the same time. Since the same color does not appear more than 20 times, so M = O(20N), then the time complexity of the whole question is O(20N log N).

Here the author introduces a useful line segment tree solution: maintain the minimum value of the interval and the number of the minimum value. Each time the matrix is ​​added, add 1 to an interval. Asking is equivalent to asking if the minimum value of the interval is 0, if it is Just add the minimum number. Lazy marks can even be permanent.

CODE

#include<set>
#include<map>
#include<queue>
#include<vector>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
#define MAXN 200005
#define DB double
#define LL long long
#define ENDL putchar('\n')
#define lowbit(x) (-(x) & (x))
#define FI first
#define SE second
#define makepair(x,y) (pair<int,int>){(x),(y)}
LL read() {
    
    
	LL f = 1,x = 0;char s = getchar();
	while(s < '0' || s > '9') {
    
    if(s=='-')f = -f;s = getchar();}
	while(s >= '0' && s <= '9') {
    
    x=x*10+(s-'0');s = getchar();}
	return f * x;
}
const int MOD = 998244353;
int n,m,i,j,s,o,k;
int Abs(int x) {
    
    return x < 0 ? -x:x;}
struct it{
    
    
	LL nm,ct; it(){
    
    nm=1e17;ct=0;}
	it(LL N,LL C){
    
    nm=N;ct=C;}
}tre[MAXN<<3];
it bing(it a,it b) {
    
    
	if(a.nm != b.nm) return a.nm < b.nm ? a:b;
	return it(a.nm,a.ct + b.ct);
}
it operator + (it a,LL b) {
    
    a.nm += b;return a;}
LL lz[MAXN<<3];int M;
void maketree(int n) {
    
    M=1;while(M<n+2)M<<=1;}
void addp(int x,it y) {
    
    
	int s = M+x;tre[s] = y; s >>= 1;
	while(s) tre[s] = bing(tre[s<<1],tre[s<<1|1])+lz[s],s >>= 1;
	return ;
}
void addtree(int l,int r,LL ad) {
    
    
	if(l > r) return ;
	int s = M+l-1,t = M+r+1;
	while(s || t) {
    
    
		if(s<M) tre[s] = bing(tre[s<<1],tre[s<<1|1])+lz[s];
		if(t<M) tre[t] = bing(tre[t<<1],tre[t<<1|1])+lz[t];
		if((s>>1) ^ (t>>1)) {
    
    
			if(!(s&1)) tre[s^1] = tre[s^1] + ad,lz[s^1] += ad;
			if(t & 1) tre[t^1] = tre[t^1] + ad,lz[t^1] += ad;
		}
		s >>= 1;t >>= 1;
	}
	return ;
}
it findtree(int l,int r) {
    
    
	if(l > r) return it();
	int s = M+l-1,t = M+r+1;
	it ls = it(),rs = it();
	while(s || t) {
    
    
		if(s < M) ls = ls + lz[s];
		if(t < M) rs = rs + lz[t]; 
		if((s>>1) ^ (t>>1)) {
    
    
			if(!(s&1)) ls = bing(ls,tre[s^1]);
			if(t & 1) rs = bing(rs,tre[t^1]);
		}
		s >>= 1;t >>= 1;
	}return bing(ls,rs);
}
int cl[MAXN];
vector<int> bu[MAXN]; 
vector<int> g[MAXN];
int d[MAXN],f[MAXN][20],dfn[MAXN],rr[MAXN],tim;
void dfs(int x,int ff) {
    
    
	d[x] = d[f[x][0] = ff] + 1;
	for(int i = 1;i <= 17;i ++) f[x][i] = f[f[x][i-1]][i-1];
	dfn[x] = ++ tim;
	for(int i = 0;i < (int)g[x].size();i ++) {
    
    
		int y = g[x][i];
		if(y != ff) {
    
    
			dfs(y,x);
		}
	}
	rr[x] = tim;
	return ;
}
vector<pair<int,int> > c[MAXN];
void addmat(int l,int r,int d,int u) {
    
    
	c[l].push_back(makepair(d,u));
	c[r+1].push_back(makepair(-d,-u));
	return ;
}
int main() {
    
    
	freopen("tree.in","r",stdin);
	freopen("tree.out","w",stdout);
	n = read();
	for(int i = 1;i <= n;i ++) {
    
    
		cl[i] = read();
	}
	for(int i = 1;i < n;i ++) {
    
    
		s = read();o = read();
		g[s].push_back(o);
		g[o].push_back(s);
	}
	dfs(1,0);
	maketree(tim);
	for(int i = 1;i <= n;i ++) {
    
    
		addp(i,it(0,1));
		int co = cl[i];
		for(int j = 0;j < (int)bu[co].size();j ++) {
    
    
			int y = bu[co][j],x = i;
			if(dfn[x] < dfn[y]) swap(x,y);
			if(dfn[y] <= dfn[x] && rr[y] >= dfn[x]) {
    
    
				int p = x;
				for(int k = 17;k >= 0;k --) {
    
    
					if(d[f[p][k]] > d[y]) p = f[p][k];
				}
				addmat(1,dfn[p]-1,dfn[x],rr[x]);
				addmat(dfn[x],rr[x],rr[p]+1,n);
			}
			else {
    
    
				addmat(dfn[y],rr[y],dfn[x],rr[x]);
			}
		}
		bu[co].push_back(i);
	}
	LL ans = 0;
	for(int i = 1;i <= n;i ++) {
    
    
		for(int j = 0;j < (int)c[i].size();j ++) {
    
    
			int ll = c[i][j].FI,rr = c[i][j].SE;
			if(ll > 0) addtree(ll,rr,1);
			else addtree(-ll,-rr,-1);
		}
		it as = findtree(i,n);
		if(as.nm == 0) ans += as.ct;
	}
	printf("%lld\n",ans);
	return 0;
}

Guess you like

Origin blog.csdn.net/weixin_43960414/article/details/115184416