• Claris’ Contest # 2 Day 2 Problem C. Dash Speed(分治+可持久化并查集+树剖)


    题面

    题解

    (std)爆栈了→_→

    我们先考虑一个简化的问题,如果只有加边的情况下如何动态维护直径

    合并两棵树时,设(a,b)(A)的直径的两个端点,(c,d)(B)的直径的两个端点,那么新的树的直径一定是(ab,ac,ad,bc,bd,cd)中的一个

    证明:新树的直径一定是原树的直径或一条经过((u,v))的链(其中((u,v))为新加的边),这条经过((u,v))的链肯定是(A)中离(u)最远的点到(u+(u,v)+v)(B)中离(v)最远的点,感性理解一下易知,其中前者必为(a)(b),后者必为(c)(d)

    于是,我们可以对于每一个连通块维护直径的两个端点,每次合并两个连通块时用六个值里的最大值更新答案,顺便用并查集维护即可

    然而现在不仅需要加边还需要删边,我们对速度进行分治,设分治区间为((l,r)),每一次将所有承受区间完全包含((l,r))的边加入,剩下的继续递归下去

    因为我们在回溯的时候需要把递归里的连通块关系给删掉,所以这里需要可持久化并查集,或者简单的说就是并查集的时候只按秩合并,不路径压缩

    //minamoto
    #include<bits/stdc++.h>
    #define R register
    #define pi pair<int,int>
    #define fi first
    #define se second
    #define ls (p<<1)
    #define rs (p<<1|1)
    #define fp(i,a,b) for(R int i=a,I=b+1;i<I;++i)
    #define fd(i,a,b) for(R int i=a,I=b-1;i>I;--i)
    #define go(u) for(int i=head[u],v=e[i].v;i;i=e[i].nx,v=e[i].v)
    #define gg(u) for(vector<eg>::iterator it=pos[u].begin();it!=pos[u].end();++it)
    template<class T>inline bool cmax(T&a,const T&b){return a<b?a=b,1:0;}
    using namespace std;
    char buf[1<<21],*p1=buf,*p2=buf;
    inline char getc(){return p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin),p1==p2)?EOF:*p1++;}
    int read(){
    	R int res=1,f=1;R char ch;
    	while((ch=getc())>'9'||ch<'0')(ch=='-')&&(f=-1);
    	for(res=ch-'0';(ch=getc())>='0'&&ch<='9';res=res*10+ch-'0');
    	return res*f;
    }
    char sr[1<<21],z[21];int K=-1,Z=0;
    inline void Ot(){fwrite(sr,1,K+1,stdout),K=-1;}
    void print(R int x){
    	if(K>1<<20)Ot();if(x<0)sr[++K]='-',x=-x;
    	while(z[++Z]=x%10+48,x/=10);
    	while(sr[++K]=z[Z],--Z);sr[++K]='
    ';
    }
    const int N=1e5+5,M=N<<5;
    struct Gr{
    	struct eg{int v,nx;}e[N<<1];int head[N],tot;
    	inline void add(R int u,R int v){e[++tot]={v,head[u]},head[u]=tot;}
    	int dep[N],top[N],fa[N],sz[N],son[N];
    	void dfs1(int u){
    		sz[u]=1,dep[u]=dep[fa[u]]+1;
    		go(u)if(v!=fa[u]){
    			fa[v]=u,dfs1(v),sz[u]+=sz[v];
    			if(sz[v]>sz[son[u]])son[u]=v;
    		}
    	}
    	void dfs2(int u,int t){
    		top[u]=t;if(!son[u])return;
    		dfs2(son[u],t);
    		go(u)if(!top[v])dfs2(v,v);
    	}
    	int LCA(int u,int v){
    		while(top[u]!=top[v]){
    			if(dep[top[u]]<dep[top[v]])swap(u,v);
    			u=fa[top[u]];
    		}
    		return dep[u]<dep[v]?u:v;
    	}
    	inline int dis(R int u,R int v){return dep[u]+dep[v]-(dep[LCA(u,v)]<<1);}
    }G;
    struct node{
    	int x,y,v;pi p;
    	node(){}
    	node(R int X,R int Y,R int V,R pi P):x(X),y(Y),v(V),p(P){}
    }st[N];
    struct eg{
    	int u,v;
    	eg(){}
    	eg(R int u,R int v):u(u),v(v){}
    };
    pi li[N];vector<eg>pos[M];
    int fa[N],ans[N],dep[N];
    int n,m,top;
    int find(int x){return fa[x]==x?x:find(fa[x]);}
    void ins(int p,int l,int r,int ql,int qr,int u,int v){
    	if(ql<=l&&qr>=r)return pos[p].push_back(eg(u,v)),void();
    	int mid=(l+r)>>1;
    	if(ql<=mid)ins(ls,l,mid,ql,qr,u,v);
    	if(qr>mid)ins(rs,mid+1,r,ql,qr,u,v);
    }
    void merge(int u,int v,int &ans){
    //	printf("%d %d ",u,v);
    	u=find(u),v=find(v);
    	int a=li[u].fi,b=li[u].se,c=li[v].fi,d=li[v].se,res=-1;
    //	printf("%d %d %d %d
    ",a,b,c,d);
    	pi p;
    	if(cmax(res,G.dis(a,b)))p=pi(a,b);
    	if(cmax(res,G.dis(a,c)))p=pi(a,c);
    	if(cmax(res,G.dis(a,d)))p=pi(a,d);
    	if(cmax(res,G.dis(b,c)))p=pi(b,c);
    	if(cmax(res,G.dis(b,d)))p=pi(b,d);
    	if(cmax(res,G.dis(c,d)))p=pi(c,d);
    	cmax(ans,res);
    	if(dep[u]<dep[v])swap(u,v);
    	st[++top]=node(u,v,0,li[u]);
    	if(dep[u]==dep[v])++dep[u],st[top].v=1;
    	fa[v]=u,li[u]=p;
    //	printf("%d
    ",res);
    }
    void del(int cur){
    	while(top>cur){
    		dep[st[top].x]-=st[top].v,fa[st[top].y]=st[top].y;
    		li[st[top].x]=st[top].p,--top;
    	}
    }
    void solve(int p,int l,int r,int res){
    	int now=top;
    	gg(p)merge(it->u,it->v,res);
    	if(l==r)ans[l]=res;
    	else{
    		int mid=(l+r)>>1;
    		solve(ls,l,mid,res);
    		solve(rs,mid+1,r,res);
    	}
    	del(now);
    }
    int x;
    int main(){
    //	freopen("testdata.in","r",stdin);
    	freopen("speed.in","r",stdin);
    	freopen("speed.out","w",stdout);
    	n=read(),m=read();
    	fp(i,1,n-1){
    		int u=read(),v=read(),l=read(),r=read();
    		G.add(u,v),G.add(v,u);
    		ins(1,1,n,l,r,u,v);
    	}
    	G.dfs1(1),G.dfs2(1,1);
    	fp(i,1,n)fa[i]=i,li[i]=pi(i,i);
    	solve(1,1,n,0);
    	while(m--)x=read(),print(ans[x]);
    	return Ot(),0;
    }
    
  • 相关阅读:
    hdu5728 PowMod
    CF1156E Special Segments of Permutation
    CF1182E Product Oriented Recurrence
    CF1082E Increasing Frequency
    CF623B Array GCD
    CF1168B Good Triple
    CF1175E Minimal Segment Cover
    php 正则
    windows 下安装composer
    windows apache "The requested operation has failed" 启动失败
  • 原文地址:https://www.cnblogs.com/bztMinamoto/p/10330319.html
Copyright © 2020-2023  润新知