• 【JZOJ6232】【20190625】喜欢最最痛


    题目

    (n)个节点的树,边权为正整数。

    从1 号点开始走一个路径并最终回到 1 号点,且这条路径经过了所有的边。

    一条路径的代价就是它经过的边的边权之和。

    可以加若干条额外边,第 i 条加的额外边的边权为 正整数(A_ i)

    注意,不一定要经过所有的额外边

    对于所有的$ K in [0, m]$,你需要输出允许加 (le K) 条额外边的最小路径代价。

    题解

    • 假设我们选了(x)条额外边,答案分为两部分:

      1.在前(K)条边里选(x)条边,使得长度和最小

      2.在原树上选(x)条边不相交的路径使得长度和最大

    • 考虑2,每次确定当前树的直径,将直径上的边全部取反,做(x)次即可

      具体用LCT维护ddp

      注意到ddp的话区间取反和翻转无法下放,但只有这两种操作

      可以预处理出splay节点取反,翻转的信息,修改的时候直接调用

    • 由于12都是凸的,所以我们直接三分求答案

    • 时间复杂度:(O(n log ^2 n + n log n * LCT ))  

    Code

    没写出来..先放YFZ的std:

    #include<bits/stdc++.h>
    using namespace std;
    const int maxn=2e5+10;
    typedef long long ll;
    typedef pair<ll,int> pii;
    const ll inf=1e18;
    int n,fa[maxn],K,C,W;
    ll ans,sum,val[maxn],anses[maxn];
    pii sval[maxn];
    vector<pii>G[maxn];
    
    struct pxx{
    	ll u,v,w;
    	pxx(){}
    	pxx(ll u,ll v,ll w):u(u),v(v),w(w){}
    	pxx operator+(const ll x)const{return pxx(u,v,w+x);}
    	pxx operator-(const ll x)const{return pxx(u,v,w-x);}
    	pxx operator+(const pxx& x)const{
    		pxx ret;
    		ret.u=u;ret.v=x.u;
    		if(ret.u<ret.v)swap(ret.u,ret.v);
    		ret.w=w+x.w;
    		return ret;
    	}
    	int operator<(const pxx& d)const{
    		if(w!=d.w)return w<d.w;
    		if(u!=d.u)return u<d.u;
    		return v<d.v;
    	}
    }; 
    //定义一条链的结构体
    struct data{
    	pxx pre,suf,ans;ll sum;
    	data(){}
    	data(pxx pre,pxx suf,pxx ans,ll sum):pre(pre),suf(suf),ans(ans),sum(sum){}
    	data operator+(const data& d)const{
    		data ret;
    		ret.pre=max(pre,d.pre+sum);
    		ret.suf=max(suf+d.sum,d.suf);
    		ret.ans=max(ans,d.ans);
    		ret.ans=max(ret.ans,suf+d.pre);
    		ret.sum=sum+d.sum;
    		return ret;
    	}
    };
    //定义一个节点的信息,类似于最大子段和
    namespace LCT{
        int ch[maxn][2],fa[maxn],tg[maxn],ftg[maxn];
    	ll val[maxn];
    	multiset<pxx> st[maxn],stans[maxn];
    	data dp[maxn];
    	pxx cpre[maxn],cans[maxn];
       	data a[2][maxn],ra[2][maxn];
       	void clr(int n){
       		for(int i=1;i<=n;++i){
       			ch[i][0]=ch[i][1]=fa[i]=tg[i]=ftg[i]=val[i]=0;
       			st[i].clear(),stans[i].clear();
    		}	
    		memset(dp,0,sizeof(data)*n);
    		memset(cpre,0,sizeof(pxx)*n);
    		memset(cans,0,sizeof(pxx)*n);
    		for(int i=0;i<2;++i){
    			memset(a[i],0,sizeof(data)*n);
    			memset(ra[i],0,sizeof(data)*n);
    		}
    	}
    	//
        void upd(int o){
        	int ls=ch[o][0],rs=ch[o][1];
        	if(o>n){
        		a[0][o]=ra[0][o]=data(dp[o].pre+val[o],dp[o].pre+val[o],dp[o].ans,val[o]);
        		a[1][o]=ra[1][o]=data(dp[o].pre-val[o],dp[o].pre-val[o],dp[o].ans,-val[o]);
    		} else {
    			a[1][o]=ra[1][o]=
    			a[0][o]=ra[0][o]=data(dp[o].pre,dp[o].pre,max(dp[o].pre+pxx(o,0,0),dp[o].ans),0);
    		}
    		if(ls){
    			for(int i=0;i<2;++i){
    				a[i][o]=a[i][ls]+a[i][o];
    				ra[i][o]=ra[i][o]+ra[i][ls];	
    			}
    		}
    		if(rs){
    			for(int i=0;i<2;++i){
    				a[i][o]=a[i][o]+a[i][rs];
    				ra[i][o]=ra[i][rs]+ra[i][o];	
    			}
    		}
        }
    	//
        void _pd(int o,int t,int ft){
    		if(ft){
    			ftg[o]^=1;
    			swap(a[0][o],a[1][o]);
    			swap(ra[0][o],ra[1][o]);
    			val[o]=-val[o];
    		}
    		if(t){
    			tg[o]^=1;
    			swap(ch[o][0],ch[o][1]);
    			swap(a[0][o],ra[0][o]);
    			swap(a[1][o],ra[1][o]);
    		}
    	}
    	//修改
        void pd(int o){
        	if(ch[o][0])_pd(ch[o][0],tg[o],ftg[o]);
        	if(ch[o][1])_pd(ch[o][1],tg[o],ftg[o]);
        	tg[o]=ftg[o]=0;
        }//下放
        bool isroot(int x){
            if(!x||!fa[x])return true;
            return ch[fa[x]][1]!=x&&ch[fa[x]][0]!=x;
        }
        void rotate(int p){
            int q=fa[p],y=fa[q],k=(ch[q][1]==p);
            if(!isroot(q))ch[y][ch[y][1]==q]=p;
            fa[ch[q][k]=ch[p][k^1]]=q;
            fa[ch[p][k^1]=q]=p,fa[p]=y;
            upd(q);
        }
        void splay(int x){
            int y;
            while(!isroot(x)){
                pd(fa[y=fa[x]]),pd(y),pd(x);
                if(!isroot(y)){
                    if((ch[fa[y]][1]==y)^(ch[y][1]==x))rotate(x);
                    else rotate(y); 
                }
                rotate(x);
            }
            pd(x),upd(x);
        }
    	//
        void uupd(int x){
        	if(x<=n){
    	    	dp[x].pre=*st[x].rbegin();
    	    	dp[x].ans=*stans[x].rbegin();
    	    	if(st[x].size()>=2){
    	    		auto it=st[x].end();
    	    		dp[x].ans=max(dp[x].ans,*prev(it)+*prev(prev(it)));
    			}
    		} else {
    			dp[x].pre=st[x].size()?*st[x].rbegin():pxx(0,0,-inf);
    			dp[x].ans=stans[x].size()?*stans[x].rbegin():pxx(0,0,-inf);
    			if(st[x].size()>=2){
    	    		auto it=st[x].end();
    	    		dp[x].ans=max(dp[x].ans,*prev(it)+*prev(prev(it))+val[x]);
    			}
    		}
    	}
    	//修改一个点的轻链信息
        void cadd(int x,int y){
      	//	printf("cadd:(%d)<%lld,%lld,%lld>
    ",y,a[0][y].ans.u,a[0][y].ans.v,a[0][y].ans.w);
        	st[x].insert(a[0][y].pre);
    		stans[x].insert(a[0][y].ans);
        	uupd(x);
    	}
    	//加入一个轻链信息
    	void del(int x,int y){
    	//	printf("del:(%d)[%lld,%lld,%lld]
    ",y,a[0][y].ans.u,a[0][y].ans.v,a[0][y].ans.w);
    		st[x].erase(a[0][y].pre);
    		stans[x].erase(a[0][y].ans);
    		uupd(x);
    	}
    	//删除一个轻链信息
        void access(int x){
    		for(int y=0;x;y=x,x=fa[x]){
    			splay(x);
    		//	printf("{%d,%d}",x,y);
    			if(ch[x][1])cadd(x,ch[x][1]);
    			if(y)del(x,y);
    			ch[x][1]=y;
    			upd(x);
    		}
    	}
    	
    	void rever(int x){
    	    access(x),splay(x);
    		_pd(x,1,0),pd(x);
    	}
    	
    	void link(int u,int v){
    		access(u),splay(u);
    		rever(v);
    		fa[v]=u;
    		cadd(u,v);
    		upd(u);
    	}
    	void mdy(int u,int v){
    		rever(u),access(v),splay(v);
    		_pd(v,0,1),pd(v);
    	}
    	void dfs(int u){
    		pd(u);
    		if(ch[u][0])dfs(ch[u][0]);
    		printf("[%d[%d,%d](%lld,%lld,%lld,%d)]",u,ch[u][0],ch[u][1],dp[u].pre.w,a[0][u].ans.w,a[1][u].ans.w,a[1][u].sum);
    		if(ch[u][1])dfs(ch[u][1]);
    	}
    };
    int ptr=0;
    void dfs(int u,int f){
    	for(auto v:G[u])if(v.first!=f){
    		dfs(v.first,u);
    		LCT::fa[v.first]=v.second;
    		LCT::cadd(v.second,v.first);
    		LCT::fa[v.second]=u;
    		LCT::upd(v.second);
    		LCT::cadd(u,v.second);
    		LCT::upd(u);
    	}
    	LCT::upd(u);
    }
    //?
    ll trsum[maxn],trcnt[maxn];
    ll calzzz(ll x){
    	ll nw=0,ans=0,nwcnt=0;
    	for(int i=21;i>=0;--i){
    		nw+=(1<<i);
    		if(nw>K||trcnt[nw]+nwcnt>x)nw-=(1<<i);
    		else nwcnt+=trcnt[nw],ans+=trsum[nw];
    	}
    	return ans+anses[x];
    }
    //BIT维护1
    ll solans(ll K){
    	int l=0,r=K-1;
    	ll ans=calzzz(K);
    	while(l<=r){
    		int mid=l+r>>1;
    		if(calzzz(mid)>calzzz(mid+1))l=mid+1,ans=min(ans,calzzz(mid+1));
    		else r=mid-1,ans=min(ans,calzzz(mid));
    	}
    	return ans;
    }
    //二分斜率求答案
    int main(){
    	freopen("love.in","r",stdin);
    	freopen("love.out","w",stdout);
    	scanf("%d%d",&n,&K);
    	sum=0;
    	ptr=n;
    	LCT::clr(2*n);
    	for(int i=1;i<=n;++i)G[i].clear();
    	for(int i=1;i<=n;++i){
    		LCT::st[i].insert(pxx(i,0,0));
    		LCT::stans[i].insert(pxx(i,i,0));
    		LCT::uupd(i),LCT::upd(i);
    	}
    	for(int i=2,u,v,w;i<=n;++i){
    		scanf("%d%d%d",&u,&v,&w);
    		++ptr;
    		LCT::val[ptr]=w;
    		LCT::uupd(ptr),LCT::upd(ptr);
    		
    		G[u].push_back(pii(v,ptr));
    		G[v].push_back(pii(u,ptr));
    		sum+=2*w;
    	}
    	dfs(1,0);
    	for(int i=1;i<=K;++i)scanf("%lld",&val[i]),sval[i]=pii(val[i],i);
    	sort(sval+1,sval+K+1);
    	int flg=0;
    	anses[0]=sum;
    	printf("%lld ",solans(0));
    	for(int i=1;i<=K;++i){
    		int R=1;
    		LCT::rever(R);
    		pxx path=LCT::a[0][R].ans;
    		sum-=path.w;
    		anses[i]=sum;
    		if(path.w==0&&!flg){
    			flg=1;
    			fprintf(stderr,"[%d]",i);
    		}
    		for(int x=lower_bound(sval+1,sval+K+1,pii(val[i],i))-sval;x<=K;x+=x&-x)
    			trsum[x]+=val[i],trcnt[x]++;
    		int u=path.u,v=path.v;
    		LCT::mdy(u,v);
    		printf("%lld ",solans(i));
    	}
    }
    
  • 相关阅读:
    如何卸载VS 2017之前版本比如VS 2013、VS2015、 VS vNext?
    在SQL Server中如何进行UPDATE TOP .....ORDER BY?
    EntityFramework 6.x和EntityFramework Core插入数据探讨
    2017-2018:时间戳
    http协议进阶(六)代理
    认清性能问题
    <转>安全测试思维导图
    RESTful API浅谈
    http协议进阶(五)连接管理
    聊聊软件测试的职业规划
  • 原文地址:https://www.cnblogs.com/Paul-Guderian/p/11112095.html
Copyright © 2020-2023  润新知