zoukankan      html  css  js  c++  java
  • 一道模拟赛题

    一道模拟赛题

    简要题意:

    • 树,单点修改,求直径,求必须选(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
    ",Query());
    		}else if(opt==2) {
    			scanf("%d",&x);
    			ll tmp=a[x];
    			UPD(x,inf);
    			printf("%lld
    ",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
    */
    
    
  • 相关阅读:
    正确理解原型和原型链
    git push之后服务器如何自动更新?
    项目工具三:Swagger导出离线版HTML5和PDF格式api文档
    项目工具二:通过SQL导出单表的结构文档
    项目工具一:把文件夹里所有子文件夹与文件按树形结构导出
    一个完整的HTTP请求过程详细
    SAAS多租户数据逻辑隔离
    JS同步执行代码
    提升JAVA代码的好“味道”
    Connection keepalive
  • 原文地址:https://www.cnblogs.com/suika/p/10165778.html
Copyright © 2011-2022 走看看