UOJ#268. 【清華集訓2016】數據交互(樹鏈剖分套線段樹套set,動態DP)

題目
細節過多。在這裏插入圖片描述
一對路徑相交當且僅當一個的lcalca在另一條路徑上。
所以我們如果詢問一條路徑相交的其他路徑的權值和。
把其他路徑p=(u,v)p=(u,v)lcalcavala+=wpval_a+=w_p[u,lca)(lca,v]valb+=wp[u,lca)和(lca,v]的val_b += w_p
那麼詢問路徑(x,y)(x,y)的權值和就是valb,lca(x,y)+vala,[x,lca)(lca,y]val_{b,lca(x,y)} + val_{a,[x,lca)\cup (lca,y]}
考慮維護一個點uu作爲詢問鏈的LCALCA時的最大答案。
在這裏插入圖片描述
可以發現所有以uulcalca的答案鏈(圖中綠鏈)可以被分解爲從uu出發的一條重鏈和一條輕鏈,重鏈下面還接着一個輕鏈,注意我們要求的答案是鏈上的valaval_a之和,+valb,u+val_{b,u}

也就是說如果我們把一條重鏈看作一個序列,對於每個點把輕鏈中最大的valaval_a和掛在那個點下面。
在這裏插入圖片描述
那麼就相當於序列上每個點作爲端點有額外的附加值,求最大子段和,這個應該是隨便維護吧(顯然有一堆細節等着你)。

那麼我們把每條重鏈的最大子段和維護好了,再維護一下重鏈的最大子段和中的最大值,那麼就可以輕鬆維護答案了!
那麼每次鏈修改,鏈修改之後lcalca點修改,點修改之後上去更新valaval_a之和的最大值(用multisetmultiset維護輕兒子)接着修改。(不要怕

但是很遺憾的是這個題不是線段樹+multiset+multiset,而是線段樹套multisetmultiset
上面的情況無法考慮重鏈部分只包含11個點的情況,因爲valaval_a會被加兩遍,所以我們需要額外考慮兩個輕鏈組合的情況,因爲我們有區間+valb+val_b,所以必須把這個值放在線段樹上才能區間修改後快速取最大值,並且在multisetmultiset更新後,在線段樹中找到這個點手動修改後pushuppushup

AC Code\mathcal AC \ Code

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

int n,m;
int info[maxn],Prev[maxn<<1],to[maxn<<1],cnt_e;
multiset<LL>ans,xsn[maxn];
void Node(int u,int v){ Prev[++cnt_e]=info[u],info[u]=cnt_e,to[cnt_e]=v; }

LL val[maxn];
LL calc(int u){
	if(xsn[u].size() == 0) return 0;
	multiset<LL>::iterator it = xsn[u].end();
	it --;
	LL r = *it;
	if(xsn[u].size() == 1) return r;
	it--;
	return r + *it;
}
struct Seg{
	vector<LL>lx,rx,mx,sm,ad,tans,ans,sam;
	int len;
	void init(int sz){
		len = sz;
		lx.resize(sz<<2),rx.resize(sz<<2);
		sm.resize(sz<<2),mx.resize(sz<<2);
		ad.resize(sz<<2),tans.resize(sz<<2);
		ans.resize(sz<<2),sam.resize(sz<<2);
	}
	
	#define lc u<<1
	#define rc lc|1
	void dtp(int u,LL v){ ad[u]+=v;rx[u]+=v,mx[u]+=v,ans[u]+=v,tans[u]+=v,sam[u]+=v; }
	void dt(int u){ if(ad[u]) dtp(lc,ad[u]),dtp(rc,ad[u]),ad[u]=0; }
	void upd(int u){
		sm[u] = sm[lc] + sm[rc];
		sam[u] = sam[lc] + sam[rc];
		lx[u] = max(lx[lc] , lx[rc] + sm[lc]);
		rx[u] = max(rx[rc] , rx[lc] + sm[rc]);
		mx[u] = max(mx[lc] , max(mx[rc] , lx[rc] + rx[lc]));
		tans[u] = max(tans[lc]  ,tans[rc]);
		ans[u] = max(mx[u] , tans[u]);
	}
	void add(int u,int l,int r,int p,LL v){
		if(l==r) return (void)(lx[u]+=v,sm[u]+=v,sam[u]+=v,rx[u]+=v,tans[u]+=v,ans[u]+=v);
		int m=l+r>>1;dt(u);
		p <= m ? add(lc,l,m,p,v) : add(rc,m+1,r,p,v);
		upd(u);
	}
	void addl(int u,int l,int r,int p,LL v){
		if(l==r) return (void)(lx[u]+=v,rx[u]+=v,ans[u]=max(tans[u],mx[u]));
		int m=l+r>>1;dt(u);
		p <= m ? addl(lc,l,m,p,v) : addl(rc,m+1,r,p,v);
		upd(u);
	}
	void addp(int u,int l,int r,int ql,int qr,LL v){
		if(ql>r||l>qr) return;
		if(ql<=l&&r<=qr) return (void)(dtp(u,v));
		int m=l+r>>1;dt(u);
		addp(lc,l,m,ql,qr,v),addp(rc,m+1,r,ql,qr,v);
		upd(u);
	}
	void mt(int u,int l,int r,int p,int v){
		if(l==r){
			tans[u] = sam[u]  + calc(v);
			ans[u] = max(ans[u] , tans[u]);
			return;
		}
		int m=l+r>>1;dt(u);
		 p <= m ? mt(lc,l,m,p,v) : mt(rc,m+1,r,p,v);
		 upd(u);
	}
}tr[maxn];


int dep[maxn],fa[maxn],tp[maxn],son[maxn],sz[maxn],id[maxn],pos[maxn],ed[maxn],tot;
void dfs1(int u,int ff){
	dep[u] = dep[fa[u] = ff] + (sz[u] = 1);
	for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff)
		dfs1(v,u),sz[u]+=sz[v],(sz[v]>sz[son[u]])&&(son[u]=v);
}
void dfs2(int u,int ff){
	pos[id[u] = ++tot] = u;
	if(son[u]) tp[son[u]]=tp[u],dfs2(son[u],u);
	else ed[tp[u]] = id[u] , ans.insert(0) , tr[tp[u]].init(id[u] - id[tp[u]] + 1);
	for(int i=info[u],v;i;i=Prev[i]) if((v=to[i])^ff && v^son[u])
		dfs2(tp[v]=v,u),xsn[u].insert(0);
	ans.insert(0);
}  

void sol(int x,int y,LL w){
	for(;tp[x]^tp[y];x=fa[tp[x]]){
		if(dep[tp[x]] < dep[tp[y]]) swap(x,y);
		ans.erase(ans.find(tr[tp[x]].ans[1]));
		tr[tp[x]].addp(1,1,ed[tp[x]]-id[tp[x]]+1,1,id[x]-id[tp[x]]+1,w);
		ans.insert(tr[tp[x]].ans[1]);
	}
	if(dep[x] < dep[y]) swap(x,y);
	if(x != y){
			ans.erase(ans.find(tr[tp[x]].ans[1]));
		tr[tp[x]].addp(1,1,ed[tp[x]]-id[tp[x]]+1,id[y]-id[tp[x]]+2,id[x]-id[tp[x]]+1,w);
			ans.insert(tr[tp[x]].ans[1]);
	}
	
	val[y] += w;
	ans.erase(ans.find(tr[tp[y]].ans[1]));
	tr[tp[y]].mt(1,1,tr[tp[y]].len,id[y]-id[tp[y]]+1,y);
	ans.insert(tr[tp[y]].ans[1]);
	bool f=0;
	for(;y;y=fa[tp[y]]){
		int p = fa[tp[y]] , t = tp[y]; LL pw = 0;
		if(p){
			pw = *xsn[p].rbegin();
			xsn[p].erase(xsn[p].find(tr[tp[y]].lx[1]));
		}
		ans.erase(ans.find(tr[tp[y]].ans[1]));
		if(!f) tr[tp[y]].add(1,1,ed[tp[y]]-id[tp[y]]+1,id[y]-id[tp[y]]+1,w),f=1;
		else tr[tp[y]].addl(1,1,ed[tp[y]]-id[tp[y]]+1,id[y]-id[tp[y]]+1,w);
		if(p){
			xsn[p].insert(tr[tp[y]].lx[1]);
			w = *xsn[p].rbegin() - pw;
			ans.erase(ans.find(tr[tp[p]].ans[1]));
			tr[tp[p]].mt(1,1,tr[tp[p]].len,id[p]-id[tp[p]]+1,p);
			ans.insert(tr[tp[p]].ans[1]);
		}
		ans.insert(tr[tp[y]].ans[1]);
	}
}

int main(){
	freopen("3.in","r",stdin);
	//freopen("3.out","w",stdout);
	scanf("%d%d",&n,&m);
	for(int i=1;i<n;i++){
		int u,v;
		scanf("%d%d",&u,&v);
		Node(u,v),Node(v,u);
	}
	dfs1(1,0),dfs2(tp[1]=1,0);
	char ch[2];
	static int x[maxn],y[maxn],w[maxn];
	for(int i=1;i<=m;i++){
		scanf("%s",ch);
		if(ch[0] == '+'){
			scanf("%d%d%d",&x[i],&y[i],&w[i]);
			sol(x[i],y[i],w[i]);
		}
		else{
			int t;
			scanf("%d",&t);
			sol(x[t],y[t],-w[t]);
		}
		printf("%lld\n",*ans.rbegin());
	}
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章