• 一道模拟赛题


    一道模拟赛题

    简要题意:

    • 树,单点修改,求直径,求必须选(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
    */
    
    
  • 相关阅读:
    echarts饼状图位置设置
    去除echarts饼状图的引导线
    VS2008里的代码如何格式化
    使用ADO如何获得SQLSERVER 2K的数据库名的列表
    CStdioFile.WriteString无法向文件写入中文
    使用ODBC 数据库 ,运行程序时 出现 “遇到不适当的参数”
    CListCtrl消息及解释
    VC的CListCtrl控件
    找不到Microsoft Access Driver(*.mdb)ODBC驱动程序的安装例程。请重新安装驱动
    WebBrowser 控件-说明
  • 原文地址:https://www.cnblogs.com/suika/p/10165778.html
Copyright © 2020-2023  润新知