• CF1464 F. My Beautiful Madness


    一棵树,有个路径集合。询问(d),问是否存在点使得它到所有路径的距离(到路径上点的距离的最小值)不超过(d)

    支持:插入路径,删除路径,询问(d)

    (nle 2*10^5)


    结论:对于每个路径求(LCA),取深度最小的(LCA)(d)级祖先(记为(v))。则如果存在交,那么(v)一定在交中。

    证明考虑反证:如果存在交且(v)不在交中,考虑此时存在的一条路径,这条路径没有覆盖到(v)。此时,要么路径在(v)子树内,它的(LCA)(d)级祖先深度一定大于(dep_v),矛盾;要么路径在(v)子树外且不覆盖(v),则此时它覆盖的地方一定不和生成(v)的路径覆盖的地方相交,矛盾。

    于是询问的时候先找出(v)。现在只需要判定(v)是否合法。

    可以求出(v)(d)级祖先(u)。先判断是否所有路径都至少有一个端点在(u)的子树内,否则存在路径覆盖不到(v)

    然后取出每条路径的(LCA)挂在树上,在(u)的子树内找(v)的最远点。发现这个东西有时候可能是假的:存在路径和((v,u))有交时。实际上这时候一定是合法的,而且通过这种方法判也不会错((LCA)(u)子树外不会被判到,(LCA)(u)子树内时(LCA)一定在路径((v,u))上)。

    于是就是个子树内最远点的问题。

    树链剖分或LCT解决。(O(nlg ^2 n))


    using namespace std;
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #include <set>
    #include <cassert>
    #define N 200005
    #define INF 100000000
    int n,m;
    struct EDGE{
    	int to;
    	EDGE *las;
    } e[N*2];
    int ne;
    EDGE *last[N];
    void link(int u,int v){
    	e[ne]={v,last[u]};
    	last[u]=e+ne++;
    }
    int fa[N],dep[N],siz[N],hs[N],top[N],ls[N],in[N],out[N],cnt;
    void init1(int x){
    	siz[x]=1;
    	for (EDGE *ei=last[x];ei;ei=ei->las)
    		if (ei->to!=fa[x]){
    			fa[ei->to]=x;
    			dep[ei->to]=dep[x]+1;
    			init1(ei->to);
    			siz[x]+=siz[ei->to];
    			if (siz[ei->to]>siz[hs[x]])
    				hs[x]=ei->to;
    		}
    }
    void init2(int x,int t){
    	top[x]=t;
    	ls[++cnt]=x;
    	in[x]=cnt;
    	if (hs[x]){
    		init2(hs[x],t);
    		for (EDGE *ei=last[x];ei;ei=ei->las)
    			if (ei->to!=fa[x] && ei->to!=hs[x])
    				init2(ei->to,ei->to);
    	}
    	out[x]=cnt;
    }
    int LCA(int u,int v){
    	while (top[u]!=top[v])
    		if (dep[top[u]]>dep[top[v]])
    			u=fa[top[u]];
    		else
    			v=fa[top[v]];
    	return dep[u]<dep[v]?u:v;
    }
    int kth(int x,int k){
    	if (k>=dep[x])
    		return 1;
    	while (dep[x]-dep[top[x]]<k){
    		k-=dep[x]-dep[top[x]]+1;
    		x=fa[top[x]];
    	}
    	return ls[in[x]-k];
    }
    struct TA{
    	int t[N];
    	void add(int x,int c){
    		for (;x<=n;x+=x&-x)
    			t[x]+=c;
    	}
    	int query(int x){
    		int r=0;
    		for (;x;x-=x&-x)
    			r+=t[x];
    		return r;
    	}
    } ta;
    void addta(int x,int c){
    	for (;x;x=fa[top[x]]){
    		ta.add(in[top[x]],c);
    		ta.add(in[x]+1,-c);
    	}
    }
    multiset<int,greater<int> > f[N],g[N];
    struct SegTree{
    	int mx[N*4];
    	void build(int k=1,int l=1,int r=n){
    		mx[k]=-INF;
    		if (l==r)
    			return;
    		int mid=l+r>>1;
    		build(k<<1,l,mid);
    		build(k<<1|1,mid+1,r);
    	}
    	void change(int x,int c,int k=1,int l=1,int r=n){
    		if (l==r){
    			mx[k]=c;
    			return;
    		}
    		int mid=l+r>>1;
    		if (x<=mid) change(x,c,k<<1,l,mid);
    		else change(x,c,k<<1|1,mid+1,r);
    		mx[k]=max(mx[k<<1],mx[k<<1|1]);
    	}
    	int query(int st,int en,int k,int l,int r){
    		if (st<=l && r<=en)
    			return mx[k];
    		int mid=l+r>>1,res=-INF;
    		if (st<=mid) res=query(st,en,k<<1,l,mid);
    		if (mid<en) res=max(res,query(st,en,k<<1|1,mid+1,r));
    		return res;
    	}
    	int query(int st,int en){
    		if (st>en)
    			return -INF;
    		return query(st,en,1,1,n);	
    	}
    } anc,sub;
    int ex[N];
    void build(){
    	for (int i=1;i<=n;++i){
    		g[i].insert(-INF);
    		f[top[i]].insert(-INF);
    	}
    	for (int i=1;i<=n;++i)
    		if (i!=1 && top[i]==i)
    			g[fa[i]].insert(-INF);
    	anc.build();
    	sub.build();
    }
    int mxdis(int u,int v){
    	int res=sub.query(in[v],out[v])-dep[v];
    	for (int x=v;dep[x]>=dep[u];x=fa[x]){
    		res=max(res,anc.query(max(in[top[x]],in[u]),in[fa[x]])+dep[v]);
    		x=top[x];
    		if (x!=1 && dep[x]-1>=dep[u]){
    			int y=fa[x];
    			auto p=g[y].begin();
    			if (*p==*f[x].begin())
    				++p;
    			res=max(res,*p+dep[v]-dep[y]*2);
    			res=max(res,sub.query(in[hs[y]],out[hs[y]])+dep[v]-2*dep[y]);
    		}
    	}
    	return res;
    }
    void modify(int w,int old,int now){
    	sub.change(in[w],now);
    	int pre=*g[w].begin();
    	g[w].erase(g[w].find(old));
    	g[w].insert(now);
    	if (pre==*g[w].begin())
    		return;
    	old=pre,now=*g[w].begin();
    	anc.change(in[w],now-dep[w]*2);
    	for (int x=w;x;x=fa[x]){
    		x=top[x];
    		int pre=*f[x].begin();
    		f[x].erase(f[x].find(old));
    		f[x].insert(now);
    		if (pre==*f[x].begin())
    			break;
    		old=pre,now=*f[x].begin();
    		if (x!=1){
    			int y=fa[x];
    			pre=*g[y].begin();
    			g[y].erase(g[y].find(old));
    			g[y].insert(now);
    			if (pre==*g[y].begin())
    				break;
    			old=pre,now=*g[y].begin();
    			anc.change(in[y],now-dep[y]*2);
    		}
    	}
    }
    void insert(int w){
    	if (ex[w]++)
    		return;
    	modify(w,-INF,dep[w]);
    }
    void erase(int w){
    	if (--ex[w])
    		return;
    	modify(w,dep[w],-INF);
    }
    struct cmps{bool operator()(int x,int y){return dep[x]>dep[y] || dep[x]==dep[y] && x<y;}};
    multiset<int,cmps> s;
    int have;
    int main(){
    	freopen("in.txt","r",stdin);
    	freopen("out.txt","w",stdout);
    	scanf("%d%d",&n,&m);
    	for (int i=1;i<n;++i){
    		int u,v;
    		scanf("%d%d",&u,&v);
    		link(u,v);
    		link(v,u);
    	}
    	init1(1);
    	init2(1,1);
    	dep[0]=-1;
    	build();
    	while (m--){
    		int op;
    		scanf("%d",&op);
    		if (op==3){
    			int d;
    			scanf("%d",&d);
    			int v=kth(*s.begin(),d),u=kth(v,d);
    			if (ta.query(in[u])!=have)
    				printf("No
    ");
    			else if (mxdis(u,v)>d)
    				printf("No
    ");
    			else
    				printf("Yes
    ");
    		}
    		else{
    			int x,y;
    			scanf("%d%d",&x,&y);
    			int lca=LCA(x,y);
    			if (op==1){
    				have++;
    				s.insert(lca);
    				addta(x,1),addta(y,1),addta(lca,-1);
    				insert(lca);
    			}
    			else{
    				have--;
    				s.erase(s.find(lca));
    				addta(x,-1),addta(y,-1),addta(lca,1);
    				erase(lca);
    			}
    		}
    	}
    	return 0;
    }
    
  • 相关阅读:
    全选+批量删除
    ssm异步上传图片
    抽象类与接口区别
    请求转发和重定向区别
    switch
    一道有点绕弯,考察的知识也是最基础的题
    线程安全之集合
    会话跟踪技术
    关于异常说明
    mybatis总结(三)之多表查询
  • 原文地址:https://www.cnblogs.com/jz-597/p/14181723.html
Copyright © 2020-2023  润新知