zoukankan      html  css  js  c++  java
  • 股神小D [点分治 or LCT]

    题面

    思路

    点分治非常$naive$,不讲了,基本思路就是记录路径最小最大值.....然后没了

    重点讲一下LCT的做法(好写不卡常)(点分一堆人被卡到飞起hhhh)

    首先,这个路径限制由边限制决定,而树中的每条边都是割边

    考虑一条边$i$,范围是$[l_i,r_i]$,那么当时间不在这个范围内的时候,这个边两边的点肯定不能跨过这条边有赚钱路径

    那么,也就是说这一条边当且仅当时间在$[l_i,r_i]$范围内的时候生效

    这样,我们可以考虑把边权范围限制变成一次加边和一次删边

    我们把一条边根据加入删除的时间分成2条,并且把$2*(n-1)$条边按照时间排序

    每次加入边的时候,统计这个边两边的联通块大小,乘起来加入答案

    删边的时候就是把边删掉

    这样子统计的话,我们容易发现,每条路径都只会被路径上加入最晚的那条边统计答案,不会有重复也不会有遗漏(不流失不蒸发

    这样就做完了,比点分治好写,而且跑的快【雾】

    Code

    依然是只提供LCT做法(实际是博主并没有写点分做法【逃】)

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #define ll long long
    using namespace std;
    inline int read(){
    	int re=0,flag=1;char ch=getchar();
    	while(!isdigit(ch)){
    		if(ch=='-') flag=-1;
    		ch=getchar();
    	}
    	while(isdigit(ch)) re=(re<<1)+(re<<3)+ch-'0',ch=getchar();
    	return re*flag;
    }
    int n,fa[200010],ch[200010][2],siz[200010],vir[200010],rev[200010];
    inline void update(int cur){
    	siz[cur]=siz[ch[cur][0]]+siz[ch[cur][1]]+1+vir[cur];
    }
    inline bool nroot(int cur){return ((ch[fa[cur]][0]==cur)||(ch[fa[cur]][1]==cur));}
    inline bool get(int cur){return ch[fa[cur]][1]==cur;}
    inline void rotate(int cur){
    	int f=fa[cur],ff=fa[f],son=get(cur),nr=nroot(f);
    	ch[f][son]=ch[cur][son^1];
    	if(ch[f][son]) fa[ch[f][son]]=f;
    	ch[cur][son^1]=f;fa[f]=cur;
    	fa[cur]=ff;
    	if(nr) ch[ff][ch[ff][1]==f]=cur;
    	update(f);update(cur);
    }
    void pushrev(int x){
    	if(!x) return;
    	swap(ch[x][0],ch[x][1]);
    	rev[x]^=1;
    }
    void pushdown(int x){
    	if(rev[x]){
    		pushrev(ch[x][0]);
    		pushrev(ch[x][1]);
    		rev[x]=0;
    	}
    }
    void push(int x){
    	if(nroot(x)) push(fa[x]);
    	pushdown(x);
    }
    void splay(int x){
    	push(x);
    	for(int f;nroot(x);rotate(x)){
    		f=fa[x];
    		if(nroot(f))
    			rotate((get(x)==get(f))?f:x);
    	}
    }
    void access(int x){
    	for(int y=0;x;y=x,x=fa[x]){
    		splay(x);
    		vir[x]+=(siz[ch[x][1]]);
    		ch[x][1]=y;
    		vir[x]-=(siz[y]);
    		update(x);
    	}
    }
    void mroot(int x){
    	access(x);splay(x);pushrev(x);
    }
    void cut(int x,int y){
    	mroot(x);access(y);splay(y);
    	ch[y][0]=0;fa[x]=0;update(y);
    }
    ll link(int x,int y){
    	mroot(x);mroot(y);
    	ll re=(ll)siz[x]*(ll)siz[y];
    	fa[y]=x;vir[x]+=(siz[y]);update(x);
    	return re;
    }
    struct edge{
    	int u,v,w,f;
    }a[400010];
    inline bool cmp(edge l,edge r){
    	if(l.w==r.w) return l.f<r.f;
    	return l.w<r.w;
    }
    int main(){
    	n=read();int i,t1,t2,t3,t4;ll ans=0;
    	for(i=1;i<=n;i++) siz[i]=1,vir[i]=0,fa[i]=ch[i][0]=ch[i][1]=rev[i]=0;
    	for(i=1;i<n;i++){
    		t1=read();t2=read();t3=read();t4=read();
    		a[i]=(edge){t1,t2,t3,0};
    		a[n+i-1]=(edge){t1,t2,t4,1};
    	}
    	sort(a+1,a+(n<<1)-1,cmp);
    	for(i=1;i<=((n-1)<<1);i++){
    		if(!a[i].f) ans+=link(a[i].u,a[i].v);
    		else cut(a[i].u,a[i].v);
    	}
    	printf("%lld
    ",ans);
    }
    
  • 相关阅读:
    iPhone开发教程之retain/copy/assign/setter/getter
    关于block使用的5点注意事项
    Block的引用循环问题 (ARC & non-ARC)
    浅谈iOS中MVVM的架构设计与团队协作
    JS学习笔记(不断更新)
    神经网络介绍
    JAVA WEB WITH IDEA
    百度地图标注多个点
    脑筋急转弯——Google 面试
    决策树分类器
  • 原文地址:https://www.cnblogs.com/dedicatus545/p/9713714.html
Copyright © 2011-2022 走看看