• 【CC】Batman and Tree


    Portal --> CC Batman and Tree

    Solution

      一开始看到很懵。。感觉无从下手(因为自己太菜了qwq)

    ​  膜拜了题解之后发现好像并没有想象的那么复杂qwq

    ​  其实冷静下来考虑dp,用(f[i])表示当前在(i)的最大能量值,然后对于一个从(x)(y)的强盗,考虑找一条路径满足(x)(y)的简单路径是其子路径,那么我们就可以用满足条件的路径的端点(f)值的最大值来更新走到的另一个端点处的新(f)

    ​  将dfs序处理出来,不难发现满足条件的路径的端点对应的应该是几段区间,具体一点就是(默认(dep[x]<=dep[y])):

    (1)(x)(y)的祖先,此时记(dw)为满足(yin subtree(dw))(dwin son(x))的节点,那么可以选路径的的端点应该一个在区间([1,st[dw]]cup[ed[dw]+1,n])内,一个在([st[y],ed[y]])

    (2)(x)不是(y)的祖先,那么此时可以选路径的端点应该一个在([st[x],ed[x]]),一个在([st[y],ed[y]])

      那么直接线段树维护一下就好了,实现一个区间取max和区间查询max即可(吉老师线段树)
      

    Code

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #define ll long long
    using namespace std;
    const int N=4e5+10,TOP=20;
    const ll inf=1LL<<60;
    struct xxx{
    	int y,nxt;
    }a[N*2];
    int h[N],lis[N],dep[N];
    int st[N],ed[N],f[N][TOP+1];
    int n,m,tot,dfn_t,dfn_t1;
    int S,P,T;
    namespace Seg{/*{{{*/
    	const int N=::N*4;
    	int ch[N][2];
    	ll tag[N],mx[N],smx[N],mn[N],smn[N];
    	int n,tot;
    	void pushup(int x){
    		if (mx[ch[x][0]]==mx[ch[x][1]]){
    			mx[x]=mx[ch[x][0]];
    			smx[x]=max(smx[ch[x][0]],smx[ch[x][1]]);
    		}
    		else{
    			int lw,up;
    			if (mx[ch[x][0]]>mx[ch[x][1]]) up=0,lw=1;
    			else up=1,lw=0;
    			mx[x]=mx[ch[x][up]];
    			smx[x]=max(smx[ch[x][up]],mx[ch[x][lw]]);
    		}
    
    		if (mn[ch[x][0]]==mn[ch[x][1]]){
    			mn[x]=mn[ch[x][0]];
    			smn[x]=min(smn[ch[x][0]],smn[ch[x][1]]);
    		}
    		else{
    			int lw,up;
    			if (mn[ch[x][0]]<mn[ch[x][1]]) lw=0,up=1;
    			else lw=1,up=0;
    			mn[x]=mn[ch[x][lw]];
    			smn[x]=min(smn[ch[x][lw]],mn[ch[x][up]]);
    		}
    	}
    	void _build(int x,int l,int r){
    		smx[x]=-inf; smn[x]=inf; tag[x]=0;
    		if (l==r){mx[x]=mn[x]=(::lis[l]==S?P:-inf);return;}
    		int mid=l+r>>1;
    		ch[x][0]=++tot; _build(ch[x][0],l,mid);
    		ch[x][1]=++tot; _build(ch[x][1],mid+1,r);
    		pushup(x);
    	}
    	void build(int _n){n=_n; tot=1; _build(1,1,n);}
    	void give_mxtag(int x,ll delta){
    		mn[x]=delta;
    		mx[x]=max(mx[x],delta);
    		tag[x]=max(tag[x],delta);
    		if (mn[x]==mx[x])
    			smn[x]=inf,smx[x]=-inf;
    		else
    			smx[x]=max(smx[x],delta);
    	}
    	void downtag(int x){
    		if (!tag[x]) return;
    		if (ch[x][0]) 
    			if (mn[ch[x][0]]<mn[x]&&mn[x]<smn[ch[x][0]])
    				give_mxtag(ch[x][0],tag[x]);
    		if (ch[x][1]) 
    			if (mn[ch[x][1]]<mn[x]&&mn[x]<smn[ch[x][1]])
    				give_mxtag(ch[x][1],tag[x]);
    		tag[x]=0;
    	}
    	void _update(int x,int l,int r,int lx,int rx,ll delta){
    		if (mn[x]>=delta) return;
    		if (l<=lx&&rx<=r&&delta<smn[x]){
    			give_mxtag(x,delta);
    			return;
    		}
    		downtag(x);
    		int mid=lx+rx>>1;
    		if (r<=mid) _update(ch[x][0],l,r,lx,mid,delta);
    		else if (l>mid) _update(ch[x][1],l,r,mid+1,rx,delta);
    		else{
    			_update(ch[x][0],l,mid,lx,mid,delta);
    			_update(ch[x][1],mid+1,r,mid+1,rx,delta);
    		}
    		pushup(x);
    	}
    	void update(int l,int r,ll delta){if (l<=r) _update(1,l,r,1,n,delta);}
    	ll _query(int x,int l,int r,int lx,int rx){
    		if (l<=lx&&rx<=r) return mx[x];
    		downtag(x);
    		int mid=lx+rx>>1;
    		if (r<=mid) return _query(ch[x][0],l,r,lx,mid);
    		else if (l>mid) return _query(ch[x][1],l,r,mid+1,rx);
    		else 
    			return max(_query(ch[x][0],l,mid,lx,mid),_query(ch[x][1],mid+1,r,mid+1,rx));
    	}
    	ll query(int l,int r){return l>r?-inf:_query(1,l,r,1,n);}
    	void _debug(int x,int lx,int rx){
    		if (lx==rx){printf("%lld ",mx[x]); return;}
    		downtag(x);
    		int mid=lx+rx>>1;
    		_debug(ch[x][0],lx,mid);
    		_debug(ch[x][1],mid+1,rx);
    	}
    	void debug(){_debug(1,1,n);}
    }/*}}}*/
    void add(int x,int y){a[++tot].y=y; a[tot].nxt=h[x]; h[x]=tot;}
    void dfs(int fa,int x,int d){
    	int u;
    	lis[++dfn_t]=x;
    	st[x]=dfn_t; dep[x]=d;
    	f[x][0]=fa;
    	for (int i=1;i<=TOP;++i) f[x][i]=f[f[x][i-1]][i-1];
    	for (int i=h[x];i!=-1;i=a[i].nxt){
    		u=a[i].y;
    		if (u==fa) continue;
    		dfs(x,u,d+1);
    	}
    	ed[x]=dfn_t;
    }
    int jump(int x,int d){
    	if (d==0) return x;
    	for (int i=0;i<=TOP;++i)
    		if (d>>i&1) x=f[x][i];
    	return x;
    }
    void debug(){
    	for (int i=1;i<=n;++i) printf("%lld ",Seg::query(i,i)); printf("
    ");
    }
    void modify(int x,int y,int r,int t){
    	ll tmp1,tmp2;
    	int dw;
    	//dep[x]<dep[y]
    	if (dep[x]>dep[y]) swap(x,y);
    	if (st[x]<=st[y]&&st[y]<=ed[x]){
    		dw=jump(y,dep[y]-dep[x]-1);
    		tmp1=max(Seg::query(1,st[dw]-1),Seg::query(ed[dw]+1,n));
    		tmp2=Seg::query(st[y],ed[y]);
    
    		if (tmp2>r){
    			Seg::update(1,st[dw]-1,tmp2+t);
    			Seg::update(ed[dw]+1,n,tmp2+t);
    		}
    		if (tmp1>r)
    			Seg::update(st[y],ed[y],tmp1+t);
    	}
    	else{
    		tmp1=Seg::query(st[x],ed[x]);
    		tmp2=Seg::query(st[y],ed[y]);
    
    		if (tmp2>r)
    			Seg::update(st[x],ed[x],tmp2+t);
    		if (tmp1>r)
    			Seg::update(st[y],ed[y],tmp1+t);
    	}
    }
    
    int main(){
    #ifndef ONLINE_JUDGE
    	freopen("a.in","r",stdin);
    #endif
    	int x,y,r,t;
    	scanf("%d",&T);
    	for (int o=1;o<=T;++o){
    		scanf("%d%d%d",&n,&S,&P);
    		memset(h,-1,sizeof(h));
    		tot=0;
    		for (int i=1;i<n;++i){
    			scanf("%d%d",&x,&y);
    			add(x,y); add(y,x);
    		}
    		dfn_t=0;
    		dfs(0,1,1);
    		Seg::build(n);
    		scanf("%d",&m);
    		for (int i=1;i<=m;++i){
    			scanf("%d%d%d%d",&x,&y,&r,&t);
    			modify(x,y,r,t);
    		}
    		printf("%lld
    ",Seg::mx[1]);
    	}
    }
    
  • 相关阅读:
    C# BulkCopy System.Data.SqlClient 数据库批量添加行数句
    SQL server 数据库优化表
    Bootstrap简介,特点,用法
    Entity Fromwork浅谈
    ADO,net 实体数据模型增、删、改,浅谈
    程序如何适应所有的难产客户
    访问数据库优化
    C#中哈希表(HashTable)的用法详解
    C# winform无边框窗体移动
    函数柯里化之加法add应用---add(1,2) add(1)(2) add(1)(2)(3) add(1,2,3)(4)
  • 原文地址:https://www.cnblogs.com/yoyoball/p/10145623.html
Copyright © 2020-2023  润新知