一道模拟赛题

一道模拟赛题

简要题意:

  • 树,单点修改,求直径,求必须选\(x\)的最长链,卡空间。

分析:

我们先把必须选的那个丢掉,发现他实际上是单点修改\(inf\)然后查树的直径。

  • 如果不卡空间的话我们可以用点分树来搞一搞,不过由于一次修改会影响到很多点不能用堆来维护只能用支持区间修改的线段树,这样空间就开不下了。
  • 我们还有动态\(DP\)
  • 对一条重链维护\(lx\)表示必须选上端点向下延伸的最长链,\(rx\)表示必须选下端点向上延伸的最长链,\(s\)表示点权和,\(mx\)表示这些点及他们轻儿子子树内直径。
  • 然后你会发现转移非常合乎逻辑,然而你要是硬写出\(dp\)式子的话却不太好分析,所以我也不知道动态\(dp\)该用哪种方法。
  • 除此之外还需要维护两个set \(s,t\)\(s\)表示向下轻儿子的链的集合,\(t\)表示轻儿子子树内直径和过当前点的最长链的集合。
  • 修改直接修改,查询直接查询。

代码:

#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#include <iostream>
#include <set>
using namespace std;
#define N 100050
#define inf (1ll<<55)
typedef long long ll;
#define db(x) cerr<<#x<<" = "<<x<<endl
#define ls p<<1
#define rs p<<1|1
int head[N],to[N<<1],nxt[N<<1],cnt,n,m,dfn[N],idf[N];
int fa[N],top[N],siz[N],son[N],sson[N];
ll f[N],g[N],a[N];
multiset<ll,greater<ll> >s[N],t[N],all;
multiset<ll,greater<ll> >::iterator it;
struct A {
	ll lx,rx,mx,s;
	A() {}
	A(ll lx_,ll rx_,ll mx_,ll s_) {lx=lx_,rx=rx_,mx=mx_,s=s_;}
	A operator + (const A &u) const {
		return A(max(lx,s+u.lx),max(u.rx,u.s+rx),max(mx,max(u.mx,rx+u.lx)),s+u.s);
	}
}tr[N<<2];
inline void add(int u,int v) {to[++cnt]=v; nxt[cnt]=head[u]; head[u]=cnt;}
void d1(int x,int y) {
	int i; fa[x]=y; siz[x]=1;
	for(i=head[x];i;i=nxt[i]) if(to[i]!=y) {
		d1(to[i],x); siz[x]+=siz[to[i]];
		if(siz[to[i]]>siz[son[x]]) son[x]=to[i];
	}
}
void d2(int x,int tp) {
	int i;
	top[x]=tp; dfn[x]=++dfn[0]; idf[dfn[0]]=x;
	g[x]=max(0ll,a[x]); s[x].insert(0ll);
	if(son[x]) {
		d2(son[x],tp),sson[x]=sson[son[x]];
	}else {
		sson[x]=x;
	}
	for(i=head[x];i;i=nxt[i]) if(to[i]!=fa[x]&&to[i]!=son[x]) {
		d2(to[i],to[i]);
		s[x].insert(f[to[i]]);
		t[x].insert(g[to[i]]);
		g[x]=max(g[x],f[x]+a[x]+f[to[i]]);
		f[x]=max(f[x],f[to[i]]);
	}
	t[x].insert(g[x]);
	g[x]=max(g[x],f[x]+a[x]+f[son[x]]);
	g[x]=max(g[x],max(*t[x].begin(),g[son[x]]));
	f[x]=max(f[son[x]],f[x]);
	f[x]+=a[x]; f[x]=max(0ll,f[x]);
}
void build(int l,int r,int p) {
	if(l==r) {
		int x=idf[l];
		tr[p]=A(*s[x].begin()+a[x],*s[x].begin()+a[x],*t[x].begin(),a[x]); return ;
	}
	int mid=(l+r)>>1;
	build(l,mid,ls); build(mid+1,r,rs);
	tr[p]=tr[ls]+tr[rs];
}
A query(int l,int r,int x,int y,int p) {
	if(x<=l&&y>=r) return tr[p];
	int mid=(l+r)>>1;
	if(y<=mid) return query(l,mid,x,y,ls);
	else if(x>mid) return query(mid+1,r,x,y,rs);
	else return query(l,mid,x,y,ls)+query(mid+1,r,x,y,rs);
}
void update(int l,int r,int x,int p) {
	if(l==r) {
		int x=idf[l];
		tr[p]=A(*s[x].begin()+a[x],*s[x].begin()+a[x],*t[x].begin(),a[x]);
		return ;
	}
	int mid=(l+r)>>1;
	if(x<=mid) update(l,mid,x,ls);
	else update(mid+1,r,x,rs);
	tr[p]=tr[ls]+tr[rs];
}
void UPD(int x,ll y) {
	all.erase(all.find(a[x]));
	all.insert(y);
	if(s[x].size()==1) {
		t[x].erase(t[x].find(max(0ll,*s[x].begin()+a[x])));
		t[x].insert(max(0ll,*s[x].begin()+y));
	}else {
		it=s[x].begin();
		ll tmp=*it;
		it++;
		tmp+=*it;
		t[x].erase(t[x].find(max(0ll,tmp+a[x])));
		t[x].insert(max(0ll,tmp+y));
	}
	a[x]=y;
	A tt;
	
	while(x) {
		update(1,n,dfn[x],1);
		x=top[x];
		tt=query(1,n,dfn[x],dfn[sson[x]],1);
		if(fa[x]) {
			if(s[fa[x]].size()==1) {
				t[fa[x]].erase(t[fa[x]].find(max(0ll,*s[fa[x]].begin()+a[fa[x]])));
			}else {
				it=s[fa[x]].begin();
				ll tmp=*it;
				it++;
				tmp+=*it;
				t[fa[x]].erase(t[fa[x]].find(max(0ll,tmp+a[fa[x]])));
			}
			t[fa[x]].erase(t[fa[x]].find(g[x]));
			s[fa[x]].erase(s[fa[x]].find(f[x]));
			f[x]=max(0ll,tt.lx);
			g[x]=max(0ll,tt.mx);
			t[fa[x]].insert(g[x]);
			s[fa[x]].insert(f[x]);
			if(s[fa[x]].size()==1) {
				t[fa[x]].insert(max(0ll,*s[fa[x]].begin()+a[fa[x]]));
			}else {
				it=s[fa[x]].begin();
				ll tmp=*it;
				it++;
				tmp+=*it;
				t[fa[x]].insert(max(0ll,tmp+a[fa[x]]));
			}
		}else {
			f[x]=max(0ll,tt.lx);
			g[x]=max(0ll,tt.mx);
		}
		x=fa[x];
	}
}
ll Query() {
	if(*all.begin()<0) return *all.begin();
	else return query(1,n,dfn[1],dfn[sson[1]],1).mx;
}
int main() {
	scanf("%d%d",&n,&m);
	int i,x,y,opt;
	for(i=1;i<n;i++) {
		scanf("%d%d",&x,&y); add(x,y); add(y,x);
	}
	for(i=1;i<=n;i++) scanf("%lld",&a[i]),all.insert(a[i]);
	d1(1,0); d2(1,1); build(1,n,1);
	while(m--) {
		scanf("%d",&opt);
		if(opt==1) {
			printf("%lld\n",Query());
		}else if(opt==2) {
			scanf("%d",&x);
			ll tmp=a[x];
			UPD(x,inf);
			printf("%lld\n",Query()-(inf-tmp));
			UPD(x,tmp);
		}else {
			scanf("%d%d",&x,&y);
			UPD(x,y);
		}
	}
}
/*
10 10
2 1
3 1
4 2
5 1
6 3
7 2
8 3
9 2
10 2
4 -6 -10 -4 10 5 -9 -6 4 4
2 4
1
1
2 6
1
2 4
1
1
1
3 7 3
*/

posted @ 2018-12-23 21:39  fcwww  阅读(188)  评论(0编辑  收藏  举报