一道模擬賽題
阿新 • • 發佈:2018-12-23
一道模擬賽題
簡要題意:
- 樹,單點修改,求直徑,求必須選\(x\)的最長鏈,卡空間。
分析:
我們先把必須選的那個丟掉,發現他實際上是單點修改\(inf\)然後查樹的直徑。
- 如果不卡空間的話我們可以用點分樹來搞一搞,不過由於一次修改會影響到很多點不能用堆來維護只能用支援區間修改的線段樹,這樣空間就開不下了。
- 我們還有動態\(DP\)。
- 對一條重鏈維護\(lx\)表示必須選上端點向下延伸的最長鏈,\(rx\)表示必須選下端點向上延伸的最長鏈,\(s\)表示點權和,\(mx\)表示這些點及他們輕兒子子樹內直徑。
- 然後你會發現轉移非常合乎邏輯,然而你要是硬寫出\(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 */