zoukankan      html  css  js  c++  java
  • [TJOI2015]旅游

    XIII.[TJOI2015]旅游

    我至今还记得做毒瘤树剖题和毒瘤线段树题时那一坨坨触目惊心的 pushuppushdown ……

    这题是可以用树剖做的。但是,我还是选择了LCT。

    在每个节点,我们维护如下值:

    mx :子树最大值

    mn :子树最小值

    lmx :从左往右走,最大收益(即要求的东西)

    rmx :从右往左走,最大收益(在翻转区间时要与lmx std::swap掉)。

    然后这是那毒瘤的压行的 pushup

    inline void pushup(int x){
    	t[x].mx=t[x].mn=t[x].val;
    	t[x].lmx=t[x].rmx=0;
    	if(lson)t[x].mx=max(t[x].mx,t[lson].mx),t[x].mn=min(t[x].mn,t[lson].mn),t[x].lmx=max(t[x].lmx,max(t[lson].lmx,t[x].val-t[lson].mn)),t[x].rmx=max(t[x].rmx,max(t[lson].rmx,t[lson].mx-t[x].val));
    	if(rson)t[x].mx=max(t[x].mx,t[rson].mx),t[x].mn=min(t[x].mn,t[rson].mn),t[x].lmx=max(t[x].lmx,max(t[rson].lmx,t[rson].mx-t[x].val)),t[x].rmx=max(t[x].rmx,max(t[rson].rmx,t[x].val-t[rson].mn));
    	if(lson&&rson)t[x].lmx=max(t[x].lmx,t[rson].mx-t[lson].mn),t[x].rmx=max(t[x].rmx,t[lson].mx-t[rson].mn);
    }
    

    lmx 中,只有右边的较大值能减去左边的较小值;在 rmx 中,只有左边的较大值能减去右边的较小值。

    完整代码放出:

    #include<bits/stdc++.h>
    using namespace std;
    int n,m;
    #define lson t[x].ch[0]
    #define rson t[x].ch[1]
    struct LCT{
    	int fa,ch[2],val,mx,mn,lmx,rmx,tag;
    	bool rev;
    }t[100100];
    inline void read(int &x){
    	x=0;
    	register char c=getchar();
    	while(c>'9'||c<'0')c=getchar();
    	while(c>='0'&&c<='9')x=(x<<3)+(x<<1)+(c^48),c=getchar();
    }
    inline int identify(int x){
    	if(x==t[t[x].fa].ch[0])return 0;
    	if(x==t[t[x].fa].ch[1])return 1;
    	return -1;
    }
    inline void REV(int x){
    	t[x].rev^=1,swap(lson,rson),swap(t[x].lmx,t[x].rmx);
    }
    inline void ADD(int x,int y){
    	t[x].val+=y,t[x].mx+=y,t[x].mn+=y,t[x].tag+=y;
    }
    inline void pushup(int x){
    	t[x].mx=t[x].mn=t[x].val;
    	t[x].lmx=t[x].rmx=0;
    	if(lson)t[x].mx=max(t[x].mx,t[lson].mx),t[x].mn=min(t[x].mn,t[lson].mn),t[x].lmx=max(t[x].lmx,max(t[lson].lmx,t[x].val-t[lson].mn)),t[x].rmx=max(t[x].rmx,max(t[lson].rmx,t[lson].mx-t[x].val));
    	if(rson)t[x].mx=max(t[x].mx,t[rson].mx),t[x].mn=min(t[x].mn,t[rson].mn),t[x].lmx=max(t[x].lmx,max(t[rson].lmx,t[rson].mx-t[x].val)),t[x].rmx=max(t[x].rmx,max(t[rson].rmx,t[x].val-t[rson].mn));
    	if(lson&&rson)t[x].lmx=max(t[x].lmx,t[rson].mx-t[lson].mn),t[x].rmx=max(t[x].rmx,t[lson].mx-t[rson].mn);
    }
    inline void pushdown(int x){
    	if(t[x].rev){
    		if(lson)REV(lson);
    		if(rson)REV(rson);
    		t[x].rev=0;		
    	}
    	if(lson)ADD(lson,t[x].tag);
    	if(rson)ADD(rson,t[x].tag);
    	t[x].tag=0;
    }
    inline void rotate(int x){
    	register int y=t[x].fa;
    	register int z=t[y].fa;
    	register int dirx=identify(x);
    	register int diry=identify(y);
    	register int b=t[x].ch[!dirx];
    	if(diry!=-1)t[z].ch[diry]=x;t[x].fa=z;
    	if(b)t[b].fa=y;t[y].ch[dirx]=b;
    	t[y].fa=x,t[x].ch[!dirx]=y;
    	pushup(y),pushup(x);
    }
    inline void pushall(int x){
    	if(identify(x)!=-1)pushall(t[x].fa);
    	pushdown(x);
    }
    inline void splay(int x){
    	pushall(x);
    	while(identify(x)!=-1){
    		register int fa=t[x].fa;
    		if(identify(fa)==-1)rotate(x);
    		else if(identify(x)==identify(fa))rotate(fa),rotate(x);
    		else rotate(x),rotate(x);
    	}
    }
    inline void access(int x){
    	for(register int y=0;x;x=t[y=x].fa)splay(x),rson=y,pushup(x);
    }
    inline void makeroot(int x){
    	access(x),splay(x),REV(x);
    }
    inline void split(int x,int y){
    	makeroot(x),access(y),splay(y);
    }
    inline void link(int x,int y){
    	makeroot(x),t[x].fa=y;
    }
    int main(){
    	read(n);
    	for(register int i=1;i<=n;i++)read(t[i].val),t[i].mn=t[i].mx=t[i].val;
    	for(register int i=1,x,y;i<n;i++)read(x),read(y),link(x,y);
    	read(m);
    	for(register int i=1,x,y,z;i<=m;i++){
    		read(x),read(y),read(z);
    		split(x,y);
    		printf("%d\n",t[y].lmx);
    		ADD(y,z);
    	}
    	return 0;
    }
    

    然后,为了复习树剖,我还写了一篇树剖的代码。然后发现,LCT比树剖可爱一百万倍!!!树剖要用重链拼出原本的路径,但是这题拼合两条链的运算不具有交换律!!!这就意味着这个拼接的东西将会非常繁琐,因为你要保证所有加上去的东西是严格按照路径顺序加上去的!并且,最后,树剖比LCT还要多敲300B!

    LCT我花了1h敲完,但是树剖我整整研究了2h……(虽然有很大原因是因为我两个月没写过树剖了

    奉上树剖代码:

    #include<bits/stdc++.h>
    using namespace std;
    #define lson x<<1
    #define rson x<<1|1
    #define mid ((l+r)>>1)
    int n,m,head[50010],cnt,dep[50010],fa[50010],son[50010],sz[50010],dfn[50010],rev[50010],top[50010],val[50010],tot;
    struct node{
    	int to,next;
    }edge[100100];
    void ae(int u,int v){
    	edge[cnt].next=head[u],edge[cnt].to=v,head[u]=cnt++;
    	edge[cnt].next=head[v],edge[cnt].to=u,head[v]=cnt++;
    }
    void dfs1(int x,int Fa){
    	fa[x]=Fa,dep[x]=dep[Fa]+1,sz[x]=1;
    	for(int i=head[x],y;i!=-1;i=edge[i].next){
    		if((y=edge[i].to)==fa[x])continue;
    		dfs1(y,x),sz[x]+=sz[y];
    		if(sz[son[x]]<sz[y])son[x]=y;
    	}
    }
    void dfs2(int x){
    	if(son[x])top[son[x]]=top[x],dfn[son[x]]=++tot,rev[tot]=son[x],dfs2(son[x]);
    	for(int i=head[x],y;i!=-1;i=edge[i].next){
    		y=edge[i].to;
    		if(y==fa[x]||y==son[x])continue;
    		top[y]=y,dfn[y]=++tot,rev[tot]=y,dfs2(y);
    	}
    }
    struct SegTree{
    	int mx,mn,lmx,rmx,tag;
    	SegTree(){
    		mx=lmx=rmx=tag=0;
    		mn=0x3f3f3f3f;
    	}
    	friend SegTree operator +(const SegTree &l,const SegTree &r){
    		SegTree x;
    		x.mx=max(l.mx,r.mx);
    		x.mn=min(l.mn,r.mn);
    		x.lmx=max(max(l.lmx,r.lmx),r.mx-l.mn);
    		x.rmx=max(max(l.rmx,r.rmx),l.mx-r.mn);
    		return x;
    	}
    }seg[200100];
    void build(int x,int l,int r){
    	if(l==r){seg[x].mn=seg[x].mx=val[rev[l]];return;}
    	build(lson,l,mid),build(rson,mid+1,r),seg[x]=seg[lson]+seg[rson];
    }
    void pushdown(int x){
    	seg[lson].mn+=seg[x].tag,seg[lson].mx+=seg[x].tag,seg[lson].tag+=seg[x].tag;
    	seg[rson].mn+=seg[x].tag,seg[rson].mx+=seg[x].tag,seg[rson].tag+=seg[x].tag;
    	seg[x].tag=0;
    }
    void modify(int x,int l,int r,int L,int R,int val){
    	if(l>R||r<L)return;
    	if(L<=l&&r<=R){seg[x].mn+=val,seg[x].mx+=val,seg[x].tag+=val;return;}
    	pushdown(x),modify(lson,l,mid,L,R,val),modify(rson,mid+1,r,L,R,val),seg[x]=seg[lson]+seg[rson];
    }
    SegTree query(int x,int l,int r,int L,int R){
    	if(l>R||r<L)return SegTree();
    	if(L<=l&&r<=R)return seg[x];
    	pushdown(x);
    	return query(lson,l,mid,L,R)+query(rson,mid+1,r,L,R);
    }
    int ask(int x,int y,int z){
    	SegTree l,r;
    	while(top[x]!=top[y]){
    		if(dep[top[x]]>dep[top[y]]){
    			SegTree tmp=query(1,1,n,dfn[top[x]],dfn[x]);
    			swap(tmp.lmx,tmp.rmx);
    			l=l+tmp;
    			modify(1,1,n,dfn[top[x]],dfn[x],z),x=fa[top[x]];
    		}
    		else r=query(1,1,n,dfn[top[y]],dfn[y])+r,modify(1,1,n,dfn[top[y]],dfn[y],z),y=fa[top[y]];
    	}
    	if(dep[x]<=dep[y])r=query(1,1,n,dfn[x],dfn[y])+r,modify(1,1,n,dfn[x],dfn[y],z);
    	else{
    		SegTree tmp=query(1,1,n,dfn[y],dfn[x]);
    		swap(tmp.lmx,tmp.rmx);
    		l=l+tmp;
    		modify(1,1,n,dfn[y],dfn[x],z);
    	}
    	return (l+r).lmx;
    }
    int main(){
    	scanf("%d",&n),memset(head,-1,sizeof(head));
    	for(int i=1;i<=n;i++)scanf("%d",&val[i]);
    	for(int i=1,x,y;i<n;i++)scanf("%d%d",&x,&y),ae(x,y);
    	dfs1(1,0),dfn[1]=rev[1]=top[1]=tot=1,dfs2(1);
    	build(1,1,n),scanf("%d",&m);
    	for(int i=1,x,y,z;i<=m;i++)scanf("%d%d%d",&x,&y,&z),printf("%d\n",ask(x,y,z));
    	return 0;
    }
    

  • 相关阅读:
    Ajax服务端框架的综合示例
    《Microsoft Sql server 2008 Internals》读书笔记目录索引
    Pro ASP.NET MVC 3 Framework
    C#客户端的异步操作
    在.net中读写config文件的各种方法
    KMP算法分析
    asp.net 4.0 + 模板引擎(NVelocity)CMS
    mvc3
    开源 Asp.net mvc 用户中心开发计划
    JqueryCMS
  • 原文地址:https://www.cnblogs.com/Troverld/p/14602043.html
Copyright © 2011-2022 走看看