GYM 102331 J Jiry Matchings

GYM 102331 J Jiry Matchings

一个比较显然的\(dp\)

\(dp_{i,k,j}\)表示以i为根的子树内有\(k\)个匹配,且第i个点的使用状态为j(用/不用)。

转移相当于做一遍\(max+\)卷积。由于这个显然是凸的,所以可以做到线性计算\(max+\)卷积。

然后可以想到分治合并子树信息。

但是考虑链的情况,时间复杂度会退化成\(O(N^2)\)

所以可以使用一个trick:重链剖分。

每次将重链取出来,然后分治算其它节点的贡献。

然后将贡献归到重链上,分治计算重链。

分析时间复杂度:

更具重链剖分的性质。

每一个点会被算\(O(\log n)\)次。

然后分治又是一个log。

所以是\(O(N\log^2N)\)

code:


/* 
{
######################
#       Author       #
#        Gary        #
#        2021        #
######################
*/
#include<bits/stdc++.h>
#define rb(a,b,c) for(int a=b;a<=c;++a)
#define rl(a,b,c) for(int a=b;a>=c;--a)
#define LL long long
#define IT iterator
#define PB push_back
#define II(a,b) make_pair(a,b)
#define FIR first
#define SEC second
#define FREO freopen("check.out","w",stdout)
#define rep(a,b) for(int a=0;a<b;++a)
#define SRAND mt19937 rng(chrono::steady_clock::now().time_since_epoch().count())
#define random(a) rng()%a
#define ALL(a) a.begin(),a.end()
#define POB pop_back
#define ff fflush(stdout)
#define fastio ios::sync_with_stdio(false)
#define check_min(a,b) a=min(a,b)
#define check_max(a,b) a=max(a,b)
using namespace std;
const int INF=0x3f3f3f3f;
typedef pair<int,int> mp;
/*}
*/
const int MAXN=200000+23;
int n;

vector<mp> g[MAXN];
struct poly{
	vector<LL> v;
	poly(int n){v.resize(n);}
	poly(){}
//	void print(){
//		cout<<v.size()<<":";
//		for(auto it:v){
//			cout<<it<<",";
//		}
//		cout<<endl;
//	}
	poly operator * (poly oth){//max + 卷积 
		if(oth.v.empty()) oth.v.PB(-1e15);
		if(v.empty()) v.PB(-1e15);
		int deg=oth.v.size()+v.size()-1;
		poly ret=poly(deg);
		int A=1,B=1;
		LL presum=v[0]+oth.v[0];
		ret.v[0]=presum;
		rb(i,1,ret.v.size()-1){
			LL RetA,RetB;
			if(A>=v.size()){
				RetA=-1e18;
			}
			else{
				RetA=v[A]-v[A-1];
			}
			if(B>=oth.v.size()){
				RetB=-1e18;
			} 
			else{
				RetB=oth.v[B]-oth.v[B-1];
			}
//			cout<<i<<" "<<A<<' '<<B<<" "<<RetA<<" "<<RetB<<' '<<endl; 
			ret.v[i]=max(RetA,RetB);
			presum+=ret.v[i];
			ret.v[i]=presum;
			if(RetA>RetB) ++A;
			else ++B;
		}
//		(*this).print();
//		oth.print();
//		ret.print();
//		cout<<endl;
		return ret;
	}
};
void expand(poly &p,int sz){
	while(p.v.size()<sz){
		p.v.PB(-1e15);
	}
}
const int MOD=9982443;
mp is[400000+233];
int val[400000+233],top[MOD],nxt[400000+233];
int cnt=0;
void insert(mp A,int val_){
	LL ha=1ll*A.FIR*A.SEC+(A.FIR^A.SEC);
	ha%=MOD;
	++cnt;
	val[cnt]=val_;
	is[cnt]=A;
	nxt[cnt]=top[ha];
	top[ha]=cnt;
}
int query(mp A){
	LL ha=1ll*A.FIR*A.SEC+(A.FIR^A.SEC);
	ha%=MOD;
	for(int now=top[ha];now;now=nxt[now]){
		if(is[now]==A) return val[now];
	}
	assert(0);
	return 19260817;
}
void chk_max(poly & A,poly B){
	int sz=B.v.size();
	expand(A,sz);
	rep(i,sz){
		check_max(A.v[i],B.v[i]);
	}
}
struct chain{
	poly ret[2][2];
	chain(){}
	chain(poly A,poly B,poly C,poly D){ret[0][0]=A,ret[0][1]=B,ret[1][0]=C,ret[1][1]=D;}
	chain merge (pair<chain,int> p,bool t1=0,bool t2=0){
		chain oth=p.FIR;
		int va=p.SEC;
		poly A[2][2],B[2][2];
		rep(i,2) rep(j,2) A[i][j]=ret[i][j],B[i][j]=oth.ret[i][j];
		poly rest[2][2];
		rep(i,2) rep(j,2) rep(i2,2) rep(j2,2){
			if(i!=j){
				if(t1) continue;
			}
			if(j2!=i2){
				if(t2) continue;
			}
			poly tmp=A[i][j]*B[i2][j2];
			expand(rest[i][j2],tmp.v.size());
			if((!j)&&(!i2))
				expand(rest[i|t1][j2|t2],tmp.v.size()+1);
			rep(z,tmp.v.size()){
				if((!j)&&(!i2)){
					check_max(rest[i|t1][j2|t2].v[z+1],tmp.v[z]+va);
				}
				check_max(rest[i][j2].v[z],tmp.v[z]);
			}
		}
		return chain(rest[0][0],rest[0][1],rest[1][0],rest[1][1]);
	}
};
int find_mid(vector<pair<poly,poly> > v){
	int all=0;
	for(auto it:v) all+=it.SEC.v.size()+it.FIR.v.size();
	mp tmp=II(INF,INF);
	int sum=0;
	rep(i,v.size()){
		sum+=v[i].FIR.v.size()+v[i].SEC.v.size();
		check_min(tmp,II(abs(all/2-sum),i));
	}
	return tmp.SEC;
}
int siz[MAXN],heavy_son[MAXN];
bool online[MAXN];
pair<poly,poly> solve(int now,int pre);
pair<poly,poly> merging(int now,vector<pair<poly,poly> > v,vector<int> son){
	if(v.empty()) return {poly(1),poly()};
	if(v.size()==1){
		poly A=v[0].FIR,B=v[0].FIR;
		chk_max(B,v[0].SEC);
		int add=query(II(son[0],now));
		A.v.PB(-1e15);
		A.v[0]=-1e15;
		rep(i,v[0].FIR.v.size()){
			A.v[i+1]=add+v[0].FIR.v[i];
		}
		return II(B,A);
	}
	int mid=find_mid(v);
	poly A,B;
	vector<pair<poly,poly > > L,R;
	vector<int> Ls,Rs;
	rb(i,0,mid){
		L.PB(v[i]);
		Ls.PB(son[i]);
	} 
	rb(i,mid+1,v.size()-1){
		R.PB(v[i]);
		Rs.PB(son[i]);
	}
	pair<poly,poly> Rl,Rr;
	Rl=merging(now,L,Ls);
	Rr=merging(now,R,Rs);
	A=Rl.FIR*Rr.FIR;
	B=Rl.SEC*Rr.FIR;
	chk_max(B,Rl.FIR*Rr.SEC);
	return II(A,B);
}
pair<poly,poly> work(int now){
	vector<pair<poly,poly> >   v;
	vector<int> son;
	for(auto it:g[now]){
		if(!online[it.FIR]){
			v.PB(solve(it.FIR,now));
			son.PB(it.FIR);
		}
	}
	return merging(now,v,son); 
}
chain work(vector<pair<poly,poly> > v,vector<int> heavy_chain){
	if(v.size()==1){
		return chain(v[0].FIR,poly(),poly(),v[0].SEC);
	}
	int md=find_mid(v);
	vector<pair<poly,poly> > l,r;
	vector<int> cl,cr; 
	rb(i,0,md){
		cl.PB(heavy_chain[i]);
		l.PB(v[i]);
	}
	int Addi=query(II(heavy_chain[md],heavy_chain[md+1]));
	rb(i,md+1,v.size()-1){
		cr.PB(heavy_chain[i]);
		r.PB(v[i]);
	}
	chain A,B;
	A=work(l,cl);
	B=work(r,cr);
//	cout<<Addi<<endl;
	chain rest=A.merge(II(B,Addi),(l.size()==1),(r.size()==1));
//	for(auto it:heavy_chain){
//		cout<<"*"<<it<<' ';
//	}
//	cout<<endl;
//	rest.ret[1][1].print();
	return rest;
}
void getheavy(int now,int pre){
	siz[now]=1;
	heavy_son[now]=0;
	for(auto it:g[now]){
		int nex=it.FIR;
		if(nex==pre) continue;
		getheavy(nex,now);
		siz[now]+=siz[nex];
		if(siz[nex]>siz[heavy_son[now]]) heavy_son[now]=nex;
	}
}
pair<poly,poly> solve(int now,int pre=0){
	getheavy(now,pre);
	vector<int> heavy_line;
	int stand=now;	
	while(stand){
		heavy_line.PB(stand);
		online[stand]=true;
		stand=heavy_son[stand];
	}
	vector<pair<poly,poly> > vp;
	for(auto it:heavy_line){
		vp.PB(work(it));
	}
//	cout<<"__"<<now<<' '<<pre<<endl;
//	for(auto it:vp){
//		it.FIR.print();
//		cout<<",\n";
//		it.SEC.print();
//		cout<<endl;
//	}
	chain ret=work(vp,heavy_line);
	pair<poly,poly> rest;
	rest.FIR=ret.ret[0][0];
	chk_max(rest.FIR,ret.ret[0][1]);
	rest.SEC=ret.ret[1][0];
	chk_max(rest.SEC,ret.ret[1][1]);
//	cout<<"##"<<now<<" "<<pre<<endl;
//	ret.ret[0][1].print();
	return rest;
}
int main(){
//	poly A,B;
//	A.v.PB(-1e15);
//	A.v.PB(5);
//	B.v.PB(-1e15);
//	B.v.PB(4);
//	A=A*B;
//	A.print(); 
//	return 0;
//	chain A,B;
//	A=chain(poly(1),poly(),poly(),poly());
//	B=chain(poly(1),poly(),poly(),poly());
//	A=A+II(B,1);
//	A.ret[0][0].print();
//	return	0; 
	scanf("%d",&n);
	rb(i,1,n-1){
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		g[u].PB(II(v,w));
		g[v].PB(II(u,w));
		insert(II(u,v),w);
		insert(II(v,u),w);
	}
	pair<poly,poly> ret=solve(1);
	expand(ret.SEC,n);
	expand(ret.FIR,n);
	chk_max(ret.FIR,ret.SEC);
	rb(i,1,n-1){
		if(ret.FIR.v[i]<-2e14){
			printf("? ");
		}
		else{
			printf("%lld ",ret.FIR.v[i]);
		}
	}
	return 0;
}
/*
4
1 2 4

4 3 5

1 4 6


*/
posted @ 2021-02-20 23:43  WWW~~~  阅读(156)  评论(0编辑  收藏  举报