uoj:【UNR #3】配對樹

題目描述

題解

考慮如果我們選出了一個偶數區間,那我們可以在樹上標出這些點,考慮貪心,如果一個子樹內能匹配的就儘量匹配,所以一個子樹延伸上去的點不會超過一個,並且我們發現每條邊最多被選一次,所以我們考慮每條邊的貢獻。考慮到確定一段區間後,如果一條邊兩端子樹內的點爲奇數的話,那這個區間下這條邊就肯定要選。所以我們考慮一個子樹內在一段偶數區間內含有奇數個點的方案數。考慮暴力,我們可以把子樹內每個點在序列上對應的位置上打上標記,然後做前綴和,如果有 llr(0l<rm)r(0 \le l < r \le m) 滿足 l,rl,r 奇偶性相同並且 sl,srs_l,s_r 奇偶性不同的話,那區間 (l,r](l,r] 就是符合要求的,於是我們線段樹處理即可。這樣是 O(n2logm)O(n^2logm) 的,於是我們可以進行 dsu on tree\text{dsu on tree} ,複雜度就是 O(nlognlogm)O(nlognlogm) 的了。(這題一定要寫讀優!)

代碼

#include <bits/stdc++.h>
#define _(d) while(d(isdigit(c=getchar())))
using namespace std;
int Rd(){char c;_(!);int x=c^48;_()x=(x<<3)+(x<<1)+(c^48);return x;}
const int N=1e5+5,P=998244353;vector<int>h[N];
int n,m,hd[N],V[N<<1],W[N<<1],nx[N<<1],t,f[N],s[2][2][N<<2],tg[N<<2],ans,sz[N],son[N];
void add(int u,int v,int w){
	nx[++t]=hd[u];V[hd[u]=t]=v;W[t]=w;
}
#define Ls k<<1
#define Rs k<<1|1
#define mid ((l+r)>>1)
void up(int k){
	for (int i=0;i<2;i++)
		for (int j=0;j<2;j++)
			s[i][j][k]=s[i][j][Ls]+s[i][j][Rs];
}
void build(int k,int l,int r){
	if (l==r){s[l&1][0][k]=1;return;}
	build(Ls,l,mid);build(Rs,mid+1,r);up(k);
}
void Dfs(int u,int fr){
	sz[u]=1;
	for (int i=hd[u],v;i;i=nx[i]){
		if ((v=V[i])==fr) continue;
		Dfs(v,u),sz[u]+=sz[v];f[v]=W[i];
		if (sz[son[u]]<sz[v]) son[u]=v;
	}
}
void push(int k){
	swap(s[0][0][k],s[0][1][k]);
	swap(s[1][0][k],s[1][1][k]);
	tg[k]^=1;
}
void down(int k){
	push(Ls);push(Rs);tg[k]=0;
}
void upd(int k,int l,int r,int L,int R){
	if (L<=l && r<=R) return push(k);
	if (tg[k]) down(k);
	if (mid>=L) upd(Ls,l,mid,L,R);
	if (mid<R) upd(Rs,mid+1,r,L,R);
	up(k);
}
void ins(int u){
	int z=h[u].size();
	for (int i=0;i<z;i++)
		upd(1,0,m,h[u][i],m);
}
void upd(int u,int fr){
	ins(u);
	for (int i=hd[u];i;i=nx[i])
		if (V[i]!=fr) upd(V[i],u);
}
void dfs(int u,int fr,int tp){
	for (int i=hd[u];i;i=nx[i])
		if (V[i]!=fr && V[i]!=son[u])
			dfs(V[i],u,0);
	if (son[u]) dfs(son[u],u,1);
	for (int i=hd[u];i;i=nx[i])
		if (V[i]!=fr && V[i]!=son[u])
			upd(V[i],u);ins(u);
	(ans+=1ll*f[u]*(1ll*s[0][0][1]*s[0][1][1]%P+1ll*s[1][0][1]*s[1][1][1]%P)%P)%=P;
	if (!tp) upd(u,fr);
}
int main(){
	n=Rd(),m=Rd();
	for (int i=1,u,v,w;i<n;i++)
		u=Rd(),v=Rd(),w=Rd(),
		add(u,v,w),add(v,u,w);
	for (int i=1;i<=m;i++)
		h[Rd()].push_back(i);
	build(1,0,m);Dfs(1,0);dfs(1,0,0);
	printf("%d\n",ans);return 0;
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章