UOJ#268. 【清华集训2016】数据交互(链分治)

传送门

题解:
首先一个显然重要的结论是两个链相交当且仅当一个链的lca在另一条链的路径上,或者lca相同。

先链剖,然后我们对于每个点计算以这个点为lca的最大路径,分为两种情况:
1.路径位于两个虚儿子中。这种情况很简单,因为每个点到根只有 O ( log n ) O(\log n) 条虚边,每个点维护一个multiset就行了。
2.一条位于实儿子中。每个点到根只有 O ( log n ) O(\log n) 个重链,每个重链用数据结构类似最大连续字段和维护一下最长路径即可。

时间复杂度 O ( n log 2 n ) O(n \log^2 n)

#include <bits/stdc++.h>
using namespace std;
typedef long long LL;

const int RLEN=1<<18|1;
inline char nc() {
	static char ibuf[RLEN],*ib,*ob;
	(ib==ob) && (ob=(ib=ibuf)+fread(ibuf,1,RLEN,stdin));
	return (ib==ob) ? -1 : *ib++;
}
inline int rd() {
	char ch=nc(); int i=0,f=1;
	while(!isdigit(ch)) {if(ch=='-')f=-1; ch=nc();}
	while(isdigit(ch)) {i=(i<<1)+(i<<3)+ch-'0'; ch=nc();}
	return i*f;
}
inline void W(LL x) {
	static int buf[50];
	if(!x) {putchar('0'); return;}
	if(x<0) {putchar('-'); x=-x;}
	while(x) {buf[++buf[0]]=x%10; x/=10;}
	while(buf[0]) {putchar(buf[buf[0]--]+'0');}
}

inline LL Max(multiset <LL> &t) {return (t.size()>=1) ? (*--t.end()) : 0;}
inline LL Sec(multiset <LL> &t) {return (t.size()>=2) ? (*--(--t.end())) : 0;}

const int N=4e5+50;
int n,m,in[N],out[N],id[N],ind;
int fa[N],len[N],top[N],sze[N],son[N],pos[N],dep[N];
int xc[N],yc[N],ww[N];
LL vf[N],virans[N],cans[N]; 
vector <int> edge[N];
multiset <LL> vir[N];
multiset <LL> ans;

struct ST1 {
	int T; LL cans;
	LL *lmx,*rmx,*sum,*mxlen;
	LL *val_tag,*mxvir;
	inline void init(int x) {
		T=x; int V=T*4;
		lmx=new LL[V]();
		rmx=new LL[V]();
		sum=new LL[V]();
		mxlen=new LL[V]();
		val_tag=new LL[V]();
		mxvir=new LL[V]();
	}
	inline void add_val(int k,int w) {rmx[k]+=w; mxlen[k]+=w;}
	inline void upt(int k) {
		lmx[k]=max(lmx[k<<1],sum[k<<1]+lmx[k<<1|1]);
		rmx[k]=max(rmx[k<<1|1],sum[k<<1|1]+rmx[k<<1]);
		sum[k]=sum[k<<1]+sum[k<<1|1];
		mxlen[k]=max(mxlen[k<<1],mxlen[k<<1|1]);
		mxlen[k]=max(mxlen[k],rmx[k<<1]+lmx[k<<1|1]);
	}
	inline void inc(int k,int l,int r,int L,int R,int w,int type) {
		if(L<=l && r<=R) {
			if(type==1) {
				lmx[k]+=w; rmx[k]+=w; sum[k]+=w;
				mxlen[k]=rmx[k];
			} else if(type==2) {
				w=w-mxvir[k];
				lmx[k]+=w; rmx[k]+=w;
				mxlen[k]=rmx[k];
				mxvir[k]+=w;
			} else {
				val_tag[k]+=w;
				add_val(k,w);
			} return;
		} 
		int mid=(l+r)>>1;
		if(R<=mid) inc(k<<1,l,mid,L,R,w,type);
		else if(L>mid) inc(k<<1|1,mid+1,r,L,R,w,type);
		else inc(k<<1,l,mid,L,R,w,type), inc(k<<1|1,mid+1,r,L,R,w,type);
		upt(k); add_val(k,val_tag[k]);
	}
	inline void add(int l,int r,int w,int type) {
		ans.erase(ans.find(cans));
		inc(1,1,T,l,r,w,type);
		ans.insert(cans=mxlen[1]);
	}
} rt[N];

struct ST2 {
	LL mx[N],val[N];
	inline void inc(int k,int l,int r,int L,int R,int w,int type) {
		if(L<=l && r<=R) {
			if(type==1) mx[k]=w+val[k];
			else val[k]+=w, mx[k]+=w;
			return;
		} int mid=(l+r)>>1;
		if(R<=mid) inc(k<<1,l,mid,L,R,w,type);
		else if(L>mid) inc(k<<1|1,mid+1,r,L,R,w,type);
		else inc(k<<1,l,mid,L,R,w,type), inc(k<<1|1,mid+1,r,L,R,w,type);
		mx[k]=max(mx[k<<1],mx[k<<1|1])+val[k];
	}
	inline LL ask(int k,int l,int r,int L,int R) {
		if(L<=l && r<=R) return mx[k];
		int mid=(l+r)>>1;
		if(R<=mid) return ask(k<<1,l,mid,L,R)+val[k];
		else if(L>mid) return ask(k<<1|1,mid+1,r,L,R)+val[k];
		else return max(ask(k<<1,l,mid,L,R),ask(k<<1|1,mid+1,r,L,R))+val[k];
	}
	inline void add(int l,int r,int w,int type) {inc(1,1,n,l,r,w,type);}
	inline LL ask(int l,int r) {return ask(1,1,n,l,r);}
} mxg,mxv;

inline void dfs(int x,int f) {
	sze[x]=1; fa[x]=f; dep[x]=dep[f]+1;
	for(auto v:edge[x]) if(v^f) {
		dfs(v,x); sze[x]+=sze[v];
		if(sze[v]>sze[son[x]]) son[x]=v;
	}
}
inline void Dfs(int x,int f) {
	top[x]=f; ++len[f];
	in[x]=++ind;
	if(son[x]) pos[son[x]]=pos[x]+1, Dfs(son[x],f);
	for(auto v:edge[x]) if(v^fa[x] && v^son[x]) 
		pos[v]=1, Dfs(v,v), vir[x].insert(0);
	out[x]=ind;
	if(x==f) rt[x].init(len[x]), ans.insert(0);
}
inline int lca(int x,int y) {
	while(top[x]^top[y]) (dep[top[x]]<dep[top[y]]) ? (y=fa[top[y]]) : (x=fa[top[x]]);
	return (dep[x]<dep[y]) ? x : y;
}

inline void opt(int x,int y,int w) {
	int l=lca(x,y);
	mxg.add(in[l],out[l],w,2);
	mxv.add(in[l],in[l],w,2);
	rt[top[l]].add(pos[l],pos[l],w,1); 
	for(int i=top[l];fa[i];i=top[fa[i]]) {
		vir[fa[i]].erase(vir[fa[i]].find(vf[i]));
		vir[fa[i]].insert(vf[i]=mxg.ask(in[i],out[i])-mxg.ask(in[fa[i]],in[fa[i]]));
		rt[top[fa[i]]].add(pos[fa[i]],pos[fa[i]],Max(vir[fa[i]]),2); 
		mxv.add(in[fa[i]],in[fa[i]],Max(vir[fa[i]])+Sec(vir[fa[i]]),1); 
	}
	for(int i=x;dep[top[i]]>=dep[top[l]];i=fa[top[i]]) {
		int L=(top[i]==top[l]) ? in[l]+1 : in[top[i]], R=in[i];
		if(L<=R) mxv.add(L,R,w,2), rt[top[i]].add(L-in[top[i]]+1,R-in[top[i]]+1,w,3); 
	}
	for(int i=y;dep[top[i]]>=dep[top[l]];i=fa[top[i]]) {
		int L=(top[i]==top[l]) ? in[l]+1 : in[top[i]], R=in[i];
		if(L<=R) mxv.add(L,R,w,2), rt[top[i]].add(L-in[top[i]]+1,R-in[top[i]]+1,w,3);
	}
}

int main() {
	n=rd(), m=rd();
	for(int i=1;i<n;i++) {
		int x=rd(), y=rd();
		edge[x].push_back(y);
		edge[y].push_back(x);
	} dfs(1,0); pos[1]=1; Dfs(1,1);
	for(int i=1;i<=m;i++) {
		char ch=nc(); while(isspace(ch)) ch=nc();
		if(ch=='+') {
			xc[i]=rd(), yc[i]=rd(), ww[i]=rd();
		} else {
			int t=rd();
			xc[i]=xc[t]; yc[i]=yc[t]; ww[i]=-ww[t];
		} opt(xc[i],yc[i],ww[i]);
		W(max(Max(ans),mxv.mx[1])), putchar('\n');
	}
	return 0;
}
发布了553 篇原创文章 · 获赞 227 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/qq_35649707/article/details/83655271