【2021省选前夕总结】

网络流

DinIc:

queue<int>QWQ;

ll bfs(){
	flow = 0;
	memset(minn,127,sizeof(minn));
	memset(pre,0,sizeof(pre));
	memset(vis,0,sizeof(vis));	
	QWQ.push(s);
	while(!QWQ.empty()){
		ll now = QWQ.front();
		//std::cout<<now<<std::endl;
		QWQ.pop();
		if(now == t)
		break;
		for(int i = head[now];i;i = e[i].next){
			ll vi = e[i].to;
			//std::cout<<vi<<" ";
			if(!vis[vi] && e[i].v && vi != pre[now]){
				QWQ.push(vi);
				pre[vi] = now;
				minn[vi] = std::min(minn[now],e[i].v);
				vis[vi] = 1;
			}
		}
		//puts("");
	}
	while(!QWQ.empty())
	QWQ.pop();
	if(!vis[t])
	return 0;
	ll now = t,cut = minn[t];
//	std::cout<<cut<<std::endl;
//	puts("");
	while(now != s){
		for(int i = head[now];i;i = e[i].next){
			if(e[i].to == pre[now]){
				e[i].v += cut;
				e[i ^ 1].v -= cut;
				break;
			}
		}
		now = pre[now];
	}
	return flow = cut;
}

EK费用流

bool spfa(){
	std::queue<int>QWQ;
	for(int i = 1;i <= n;++i){
		minc[i] = 0x3f3f3f3f,vis[i] = 0;
	}
	QWQ.push(s);
	vis[s] = 1;
	minw[s] = 0x3f3f3f3f;
	minc[s] = 0;
	while(!QWQ.empty()){
		int now = QWQ.front();
		QWQ.pop();
		vis[now] = 0;
		for(int i = head[now];i;i = e[i].next){
			if(e[i].v){
				int v = e[i].to;
				if(minc[v] > minc[now] + e[i].c){
					minc[v] = minc[now] + e[i].c;
					pre[v] = i;
					minw[v] = std::min(minw[now],e[i].v);
					if(!vis[v])vis[v] = 1,QWQ.push(v);
				}
			}
		}
	}
	return minc[t] != 0x3f3f3f3f;
}

int answ,ansc;

void up(){
	int now = t;
	answ += minw[t];
	ansc += minc[t] * minw[t];
 	while(now != s){
		e[pre[now]].v -= minw[t];
		e[pre[now] ^ 1].v += minw[t];
		now = e[pre[now] ^ 1].to;
	}
}

\(tarjan缩点\ 30min\)
每天一个抱铃小技巧:low[u] == std::min(low[u],dfn[v]);这个居然不会报错
割点:仿照强连通分量,判断条件改为 low[v]>=dfn[u](v是搜索树上新根)
割边:仿照强连通分量,判断条件改为 low[v]>dfn[u]
无向图注意由于是维护的搜索树,不要搜到父亲去,割点时,如果搜索树根只是一个儿节点(搜索树上的),那么要强制把他设为非割点。

数据结构

胆大心细,暴力操作。
平衡树/线段树五问:
1.每个节点需要记录那些信息
2.需要那些标记
3.下传标记怎么做
4.区间整体修改怎么搞
5.如何合并区间

Fhq_treap

ll ch[A][2],val[A],cv[A],siz[A],cnt;
#define l(x) ch[x][0]
#define r(x) ch[x][1]
#define v(x) val[x]
#define c(x) cv[x]
#define s(x) siz[x]

void up(ll x){s(x) = 1 + s(l(x)) + s(r(x));}

ll randoom(){return rand() << 15 | rand();}

ll newcode(ll x){s(++cnt) = 1,v(cnt) = x,c(cnt) = randoom();return cnt;}

void split(ll now,ll k,ll &x,ll &y){
	if(!now){x = y = 0;return;}
	if(v(now) <= k) x = now,split(r(now),k,r(now),y);
	else
	y = now,split(l(now),k,x,l(now));
	up(now);
}

ll merge(ll x,ll y){
	if(!x || !y)return x + y;
	if(c(x) < c(y)){
		r(x) = merge(r(x),y);
		up(x);return x;
	}
	else{
		l(y) = merge(x,l(y));
		up(y);return y;
	}
}

ll root,x,y,z,cn;

void insert(ll a){
	cn ++ ;
	split(root,a,x,y);
	root = merge(merge(x,newcode(a)),y);
}

void del(ll a){
	cn -- ;
	split(root,a,x,z);
	split(x,a - 1,x,y);
	y = merge(l(y),r(y));
	root = merge(x,merge(y,z));
}

ll find(ll a){
	split(root,a - 1,x,y);
	ll ans = s(x) + 1;
	root = merge(x,y);
	return ans;
}

ll kth(ll now,ll k){
	if(k <= s(l(now)))return kth(l(now),k);
	else
	if(k == s(l(now)) + 1)return now;
	else
	return kth(r(now),k - s(l(now)) - 1);
}

主席树:

ll build(ll l,ll r){
   ll now = ++cnt;
   if(l == r){
   	tree[now].va = 0;
    return now;
   }
   tree[now].l = build(l,mid);
   tree[now].r = build(mid + 1,r);
   return now;
}

ll up(ll now){
   tree[now].va = tree[tree[now].l].va + tree[tree[now].r].va;
}

ll update(ll pre,ll l,ll r,ll k){
   ll now = ++cnt;
   tree[now].l = tree[pre].l;
   tree[now].r = tree[pre].r;
   tree[now].va = tree[pre].va + 1;
   if(l < r)
   if(k <= mid)
   tree[now].l = update(tree[pre].l,l,mid,k);
   else
   tree[now].r = update(tree[pre].r,mid + 1,r,k);
   return now;
}

ll query(ll u,ll v,ll l,ll r,ll k){
	if(l >= r) return l;
	//std::cout<<u<<" "<<v<<" "<<tree[tree[v].l].va<<" "<<tree[tree[u].l].va<<std::endl;
	ll x = tree[tree[v].l].va - tree[tree[u].l].va;
	if(x >= k) return query(tree[u].l,tree[v].l,l,mid,k);
	else return query(tree[u].r,tree[v].r,mid + 1,r,k - x);
} //静态区间kth

线段树合并:

int merge(int a,int b,int x,int y) {
	if(!a) return b;if(!b) return a;
	if(x==y) {d[a]+=d[b];t[a]=x;return a;}
	int mid=x+y>>1;
	l[a]=merge(l[a],l[b],x,mid),r[a]=merge(r[a],r[b],mid+1,y);
	pushup(a);return a;
}//破坏结构,省空间,离线
int merge(int a,int b,int x,int y) {
	if(!a) return b;if(!b) return a;
	int root=++cnt;
	if(x==y) {d[root]=d[a]+d[b];t[root]=x;return root;}
	int mid=x+y>>1;
	l[root]=merge(l[a],l[b],x,mid),r[root]=merge(r[a],r[b],mid+1,y);
	pushup(root);return root;
}//类似于主席树,炸空间

cdq分治:

struct P{
	ll x,y,z,id;
}e[N];

ll ans[N],unq[N],f[N];
ll t[N * 2];

ll n,k;

void add(ll x,ll p){
	for(int i = x;i <= k;i += lowbit(i))
	t[i] += p;
}

int get(ll x){
	ll ans = 0;
	for(int i = x;i;i -= lowbit(i))
	ans += t[i];
	return ans;
}

bool cmp(P t,P s){
	if(t.x != s.x)
	return t.x < s.x;
	if(t.y != s.y)
	return t.y < s.y;
	return t.z < s.z;
}

bool cmp1(P t,P s){
	if(t.y != s.y)
	return t.y < s.y;
	if(t.z != s.z)
	return t.z < s.z;	
	return t.x < s.x;
}

void cdq(ll l,ll r){
	if(l == r)
	return;
	int mid = (l + r) >> 1;
	cdq(l,mid),cdq(mid + 1,r);
	std::sort(e + l,e + r + 1,cmp1);
	for(int i = l;i <= r;++i)
	if(e[i].x <= mid)
	add(e[i].z,1);
	else
	ans[e[i].id] += get(e[i].z);
	for(int i = l;i <= r;++i){
	if(e[i].x <= mid)
	add(e[i].z,-1);
//	printf("%lld %lld\n",e[i].x,ans[e[i].id]);
	}
}

int main(){
	scanf("%lld%lld",&n,&k);
	for(int i = 1;i <= n;++i)
	scanf("%lld%lld%lld",&e[i].x,&e[i].y,&e[i].z),e[i].id = i;
	std::sort(e + 1,e + n + 1,cmp);
	for(int i = 1,j;i <= n;){
		j = i + 1;
		while(j <= n && e[j].x == e[i].x && e[j].y == e[i].y && e[j].z == e[i].z)
		j ++ ;
		while(i < j)
		unq[e[i].id] = e[j - 1].id,i ++ ;
	}
	for(int i = 1;i <= n;++i)
	e[i].x = i;
	cdq(1,n);
	for(int i = 1;i <= n;++i)
	f[ans[unq[e[i].id]]] ++ ;
	for(int i = 0;i < n;++i)
	printf("%lld\n",f[i]);
} 

01tire什么的就不写的,到时候复习一点笔记好了

数论

exgcd

LL exgcd(LL a,LL b,LL &x,LL &y){
	LL d=a; if(b==0) x=1,y=0; else{
		d=exgcd(b,a%b,y,x),y-=a/b*x;
	}
	return d;
}

筛法:

	mu[1] = 1;
	for(int i = 2;i <= 10000000;++i){
		if(!flag[i]) prime[++cnt] = i,mu[i] = -1,phi[i] = i - 1;
		for(int j = 1;j <= cnt && i * prime[j] <= 10000000;++j){
			flag[i * prime[j]] = 1;
			if(i % prime[j] == 0){phi[i * prime[j]] = phi[i] * prime[j];break;}
			phi[i * prime[j]] = phi[i] * (prime[j] - 1);
			mu[i * prime[j]] = -mu[i];
		}
	}

杜教筛

到时候看博客

字符串

马拉车

	s[0] = '~';
	a = getchar();
	while(a <= 'z' && a >= 'a'){
		s[++len] = '|';
		s[++len] = a;
		a = getchar();
	}
	s[++len] = '|';
	for(int i = 1;i <= len;++i){
		if(m + ans[m] >= i)
		ans[i] = std::min(m + ans[m] - i,ans[m * 2 - i]);
		while(s[i - ans[i]] == s[i + ans[i]]) ans[i] ++ ;
		if(ans[i] + i > m + ans[m])m = i;
		if(fans < ans[i])
		fans = ans[i];
	} 
	std::cout<<fans - 1;

最小表示法

	scanf("%lld",&n);
	for(int i = 1;i <= n;++i)
	scanf("%lld",&a[i]);
	for(int i = n + 1;i <= 2 * n;++i)
	a[i] = a[i - n];
	int j = 1,i = 2,k,tmp;
	while(i <= n){
		k = 0;
		while(a[i + k] == a[j + k])
		k += 1;
		if(a[i + k] < a[j + k])
		tmp = i,i = std::max(i + 1,j + k + 1),j = tmp;
		else
		i = i + k + 1;
	}
	for(int l = 1;l <= n;++l)
	std::cout<<a[j + l - 1]<<" ";

AC自动机

ll n,cnt;
int to[1000005][50],end[1000005],fail[1000005];
char a[1000005];

void insert(){
	ll now = 0;
	ll n = strlen(a + 1);
	for(int i = 1;i <= n;++i){
		if(!to[now][a[i] - 'a'])
		to[now][a[i] - 'a'] = ++ cnt ;
		now = to[now][a[i] - 'a'];
	}
	end[now] ++ ;
}

std::queue<int>	QWQ ;

void get(){
	for(int i = 0;i < 26;++i)
	if(to[0][i]) fail[to[0][i]] = 0,QWQ.push(to[0][i]);
	while(! QWQ.empty()){
		ll u = QWQ.front();QWQ.pop();
		for(int i = 0;i < 26;++i)
		if(to[u][i]) fail[to[u][i]] = to[fail[u]][i],QWQ.push(to[u][i]);
		else to[u][i] = to[fail[u]][i]; 
	}
}

int query(){
	ll len = strlen(a + 1),now = 0,ans = 0;
	for(int i = 1;i <= len;++i){
		now = to[now][a[i] - 'a'];
		for(int t = now;t && end[t] != -1;t = fail[t]) ans += end[t],end[t] = -1;
	}
	return ans;
}

SA:

const int maxn = 1e6 + 5;
int rk[maxn], RK[maxn];
int sa[maxn], SA[maxn];
int bac[maxn], n, h[maxn], height[maxn];
int rmq[maxn][18], bin[1 << 18];
char str[maxn];

void getsa(char *str, int n, int alp = 256) {
    for (int i = 0; i <= alp; i++) bac[i] = 0;
    for (int i = 1; i <= n; i++) ++bac[str[i]];
    for (int i = 1; i <= alp; i++) bac[i] += bac[i - 1];
    for (int i = 1; i <= n; i++) sa[bac[str[i]]--] = i;
    for (int i = 1; i <= n; i++) rk[sa[i]] = rk[sa[i - 1]] + (str[sa[i]] != str[sa[i - 1]]);

    for (int p = 1; p <= n; p <<= 1)
    {
        for (int i = 1; i <= n; i++) bac[rk[sa[i]]] = i;
        for (int i = n; i >= 1; i--) if (sa[i] > p) SA[bac[rk[sa[i] - p]]--] = sa[i] - p;
        for (int i = n; i > n - p; i--) SA[bac[rk[i]]--] = i;
        #define comp(x, y) (rk[x] != rk[y] || rk[x + p] != rk[y + p])
        for (int i = 1; i <= n; i++) RK[SA[i]] = RK[SA[i - 1]] + comp(SA[i], SA[i - 1]);
        for (int i = 1; i <= n; i++) sa[i] = SA[i], rk[i] = RK[i];
        if (rk[sa[n]] >= n) return ;
    }
}
void geth(char *str, int n) {
    for (int i = 1; i <= n; i++)
    {
        int j = sa[rk[i] - 1], k = max(0, h[i - 1] - 1);
        while (str[i + k] == str[j + k] && str[i + k]) ++k;
        h[i] = height[rk[i]] = k;
    }
    for (int j = 0; j < 18; j++)
    for (int i = 1 << j; i < (1 << j + 1); i++) bin[i] = j;
    for (int i = 1; i <= n; i++) rmq[i][0] = height[i];
    for (int j = 1; j < 18; j++)
    for (int i = 1 << j; i <= n; i++)
        rmq[i][j] = min(rmq[i - (1 << j - 1)][j - 1], rmq[i][j - 1]);
}
int lcp(int x, int y) {
    int u = rk[x], v = rk[y];
    if (u > v) swap(u, v);
    int j = bin[v - u];
    return min(rmq[v][j], rmq[u + (1 << j)][j]);
}

树上问题

树链剖分

ll n,m,root,p;
ll v[200000],head[200000];
ll cnt = 0;

void add(ll x,ll y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}

int dep[200000],fa[200000],siz[200000],gson[200000];

int dfncnt,dfn[200000],top[200000],num[200000];

void dfs2(int u,int t){
	top[u] = t;
	dfn[u] = ++dfncnt;
	num[dfncnt] = v[u];
	if(!gson[u])return;
	dfs2(gson[u],t);
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == fa[u] || v == gson[u])
		continue;
		dfs2(v,v);
	}
}

void dfs(ll u,ll f){
	fa[u] = f;
	dep[u] = dep[f] + 1;
	siz[u] = 1;
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == f)
		continue;
		dfs(v,u);
		siz[u] += siz[v];
		if(siz[v] > siz[gson[u]])
		gson[u] = v;
	}
}

struct Seg{
	struct E{
		ll l,r,v,m;
	}t[400000];
	#define l(x) t[x].l
	#define r(x) t[x].r
	#define v(x) t[x].v
	#define m(x) t[x].m
	#define mid ((l + r) >> 1)
	void up(ll now){v(now) = (v(l(now)) + v(r(now))) % p;}
	void push(ll now,ll l,ll r){
	m(l(now)) += m(now);
	m(r(now)) += m(now);
	v(l(now)) += m(now) * (mid - l + 1);
	v(r(now)) += m(now) * (r - mid);
	v(l(now)) %= p,m(l(now)) %= p;
	v(r(now)) %= p,m(r(now)) %= p;
	m(now) = 0;}
	ll build(ll l,ll r){
		ll now = ++cnt;
		m(now) = 0;
		if(l == r){
			v(now) = num[l];
			return cnt;
		}
		l(now) = build(l,mid);
		r(now) = build(mid + 1,r);
		up(now);
		return now;
	}
	void change(ll now,ll l,ll r,ll nl,ll nr,ll s){
		push(now,l,r);
		if(nl <= l && r <= nr){
			v(now) += (r - l + 1) * s;
			m(now) += s;
			v(now) %= p;
			m(now) %= p;
			return ;
		}
		if(nl <= mid)
			change(l(now),l,mid,nl,nr,s);
		if(nr > mid)
			change(r(now),mid + 1,r,nl,nr,s);
		up(now);
	}
	ll q(ll now,ll l,ll r,ll nl,ll nr){
		push(now,l,r);
		ll ans = 0;
		if(nl <= l && r <= nr)
		return v(now) % p;
		if(nl <= mid)
		ans = (ans + q(l(now),l,mid,nl,nr)) % p;
		if(nr > mid)
		ans = (ans + q(r(now),mid + 1,r,nl,nr)) % p;
		up(now);
		return ans;
	}
}Q;

int main(){
	scanf("%lld%lld%lld%lld",&n,&m,&root,&p);
	for(int i = 1;i <= n;++i){
		scanf("%lld",&v[i]);
	}
	for(int i = 1;i <= n - 1;++i){
		ll x,y;
		scanf("%lld%lld",&x,&y);
		add(x,y);
		add(y,x);
	}
	dfs(root,0);
	dfs2(root,root);
	cnt = 0;
	int z = Q.build(1,n);
//	for(int i = 1;i <= n;++i){
//		std::cout<<fa[i]<<" "<<dep[i]<<" "<<top[i]<<" "<<dfn[i]<<" "<<siz[i]<<" "<<gson[i]<<std::endl;
//	}
	for(int i = 1;i <= m;++i){
		ll opt,x,y,z;
		scanf("%lld",&opt);
		if(opt == 1){
			scanf("%lld%lld%lld",&x,&y,&z);
			z %= p;
			while(top[x] != top[y]){
				if(dep[top[x]] < dep[top[y]])std::swap(x,y);
				Q.change(1,1,n,dfn[top[x]],dfn[x],z);
				x = fa[top[x]];
			}
			if(dep[x] > dep[y]) std::swap(x,y);
			Q.change(1,1,n,dfn[x],dfn[y],z);
		}
		if(opt == 2){
			scanf("%lld%lld",&x,&y);
			ll ans = 0;
			while(top[x] != top[y]){
				if(dep[top[x]] < dep[top[y]])std::swap(x,y);
				ans = (ans + Q.q(1,1,n,dfn[top[x]],dfn[x])) % p;
				x = fa[top[x]];
			}
			if(dep[x] > dep[y])
			std::swap(x,y);
			ans = (ans + Q.q(1,1,n,dfn[x],dfn[y])) % p;
			std::cout<<ans % p<<std::endl;
		}
		if(opt == 3){
			scanf("%lld%lld",&x,&z);
			Q.change(1,1,n,dfn[x],dfn[x] + siz[x] - 1,z);
		}
		if(opt == 4){
			scanf("%lld",&x);
			std::cout<<Q.q(1,1,n,dfn[x],dfn[x] + siz[x] - 1) % p<<std::endl;
		}
	}
}//一个普通的维护路径权和的代码,还是写的不够快

虚树:

struct P{
	ll to,next,v;
}e[M],e2[M];

ll cnt,head[N],dfn[N],idf[N],top[N],Minn[N],dep[N],fa[N],siz[N],son[N];
ll dcnt;
ll cnt2,head2[N],DP[N];

void add(ll x,ll y,ll v){
	e[++cnt].to = y;
	e[cnt].v = v;
	e[cnt].next = head[x];
	head[x] = cnt;
}

void add2(ll x,ll y){
	e2[++cnt2].to = y;
	e2[cnt2].next = head2[x];
	head2[x] = cnt2;
}

void dfs1(ll now,ll f){
	fa[now] = f;
	dep[now] = dep[f] + 1;
	siz[now] = 1; 
	for(int i = head[now];i;i = e[i].next){
		ll v = e[i].to;
		if(v != f){
		Minn[v] = std::min(Minn[now],e[i].v);
		dfs1(v,now);
		siz[now] += siz[v];
		if(siz[v] > siz[son[now]])
		son[now] = v;
		}
	}
}

void dfs2(ll now,ll t){
	top[now] = t;
	dfn[now] = ++dcnt;
	idf[dfn[now]] = now;
	if(!son[now])
	return;
	dfs2(son[now],t);
	for(int i = head[now];i;i = e[i].next){
		ll v = e[i].to;
		if(v == fa[now] || v == son[now])
		continue;
		dfs2(v,v);
	}
}

ll lca(ll x,ll y){
	while(top[x] != top[y]){
		if(dep[top[x]] < dep[top[y]])
		std::swap(x,y);
		x = fa[top[x]];
	}
	if(dep[x] > dep[y])
	std::swap(x,y);
	return x;
}

ll stack[N];

void build(){
	cnt2 = 0;
	std::sort(stack + 1,stack + stack[0] + 1);
	ll s = stack[0];
	for(int i = 2;i <= s;++i)
	stack[++stack[0]] = dfn[lca(idf[stack[i]],idf[stack[i - 1]])];
	std::sort(stack + 1,stack + stack[0] + 1);
	s = std::unique(stack + 1,stack + stack[0] + 1) - stack - 1;
	for(int i = 2;i <= s;++i)
	add2(lca(idf[stack[i]],idf[stack[i - 1]]),idf[stack[i]]);
}

bool qr[N];

void dfs(ll now){
	ll s = 0;
	DP[now] = Minn[now];
	for(int i = head2[now];i;i = e2[i].next){
		ll v = e2[i].to;
		dfs(v);
		s += DP[v];
	}
	if(s && !qr[now])
	DP[now] = std::min(s,DP[now]);
	else
	qr[now] = 0;
	head2[now] = 0;
}

淀粉质:

struct P{
	int to,next,v;
}e[M];

int cnt,head[N],dis[N],siz[N],dp[N],rev[N];
bool vis[N];

void add(int x,int y,int v){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	e[cnt].v = v;
	head[x] = cnt;
}

ll n,k,rt,sum;

void getrt(ll u,ll fa){
	siz[u] = 1,dp[u] = 0;
	for(int i = head[u];i;i = e[i].next){
		ll v = e[i].to;
		if(v == fa || vis[v])
		continue;
		getrt(v,u);
		siz[u] += siz[v];
		dp[u] = std::max(dp[u],siz[v]);
	}
	dp[u] = std::max((ll)dp[u],sum - siz[u]);
	if(dp[u] < dp[rt])
	rt = u;
}

ll ans = 0;
ll tot = 0;

void getdis(ll u,ll fa){
	rev[++tot] = dis[u];
	for(int i = head[u];i;i = e[i].next){
		ll v = e[i].to;
		if(v == fa || vis[v])
		continue;
		dis[v] = dis[u] + e[i].v;
		getdis(v,u);
	}
}

ll doit(ll u,ll s){
	tot = 0,dis[u] = s,getdis(u,0);
	std::sort(rev + 1,rev + tot + 1);
	ll l = 1,r = tot;
	ll ans = 0;
	while(l <= r)
	if(rev[l] + rev[r] <= k)
	ans += r - l,++l;
	else
	--r;
	return ans;
}

void solve(ll u){
	vis[u] = 1,ans += doit(u,0);
	for(int i = head[u];i;i = e[i].next){
		ll v = e[i].to;
		if(vis[v])continue;
		ans -= doit(v,e[i].v);
		sum = siz[v],dp[0] = n,rt = 0;
		getrt(v,u),solve(rt);
	}
}

树上启发式合并

struct P{
	ll to,next;
}e[M];

int cnt,C[N],head[N],c[N],siz[N],gson[N];
ll ans[N],fans[N];

void add(int x,int y){
	e[++cnt].to = y;
	e[cnt].next = head[x];
	head[x] = cnt;
}

ll n;

void dfs(int u,int fa){
	siz[u] = 1;
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == fa)
		continue;
		dfs(v,u);
		siz[u] += siz[v];
		if(siz[v] > siz[gson[u]])
		gson[u] = v;
	}
}

std::queue<int>QWQ;

ll maxx;

void clear(){
	maxx = 0;
	while(!QWQ.empty()){
		C[QWQ.front()] = 0;
		QWQ.pop();
	}
}

ll t;

void init(int u,int fa){
	QWQ.push(c[u]);
	C[c[u]] ++ ;
	if(C[c[u]] > maxx)
	fans[t] = c[u],maxx = C[c[u]];
	else
	if(C[c[u]] == maxx)
	fans[t] += c[u];
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == fa || v == gson[t])
		continue;
		init(v,u);
	}
}

void solve(int u,int fa){
	for(int i = head[u];i;i = e[i].next){
		int v = e[i].to;
		if(v == fa || v == gson[u])
		continue;
		solve(v,u);
		clear();
	}
	if(gson[u])
	solve(gson[u],u);
	t = u;
	fans[u] = fans[gson[u]];
	init(u,fa);
}
原文地址:https://www.cnblogs.com/dixiao/p/14629784.html