[BZOJ]4229: 选择 离线+树链剖分

Description

现在,我想知道自己是否还有选择。
给定n个点m条边的无向图以及顺序发生的q个事件。
每个事件都属于下面两种之一:
1、删除某一条图上仍存在的边
2、询问是否存在两条边不相交的路径可以从点u出发到点v

Solution

我可能是个SB……
其实我以前还做过这题,BZOJ的星球联盟,但是我忘了,想的做法是类似BZOJ1969的。
正常的做法是倒着加边,然后把树上的一段点缩成一个,用LCT或并查集维护。
我的做法也是倒着加边,两点没有连通就连起来,已连通就把两点路径上的边都打上标记,询问输出Yes就是两点路径上的边都被打标记,其实本质好像是一样的。
询问如果是同一个点不知道怎么搞,数据好像也没有……那不管了……

Code

#include<bits/stdc++.h>
using namespace std;
#define LL long long
#define pa pair<int,int>
const int Maxn=100010;
const int inf=2147483647;
const int mod=1001001;
int read()
{
	int x=0,f=1;char ch=getchar();
	while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
	while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+(ch^48),ch=getchar();
	return x*f;
}
int n,m,q,rt[Maxn],_rt[Maxn],fa[Maxn],dfn[Maxn],DFN=0,son[Maxn],dep[Maxn],sz[Maxn],top[Maxn];bool mark[Maxn];
int findrt(int x){return((rt[x]==x)?x:rt[x]=findrt(rt[x]));}
struct Edge{int y,next;}e[Maxn<<2];int last[Maxn],len=0;
void ins(int x,int y){int t=++len;e[t].y=y;e[t].next=last[x];last[x]=t;}
struct Seg{int l,r,lc,rc,c;}tr[Maxn<<1];int tot=0;
void Modify(int x){tr[x].c=true;}
void up(int x){tr[x].c=tr[tr[x].lc].c&tr[tr[x].rc].c;}
void down(int x){if(tr[x].c)Modify(tr[x].lc),Modify(tr[x].rc);}
void build(int l,int r)
{
	int x=++tot;tr[x].l=l;tr[x].r=r;tr[x].c=false;
	if(l==r)return;
	int mid=l+r>>1;
	tr[x].lc=tot+1,build(l,mid);
	tr[x].rc=tot+1,build(mid+1,r);
	up(x);
}
void modify(int x,int l,int r)
{
	if(l>r)return;
	if(tr[x].l==l&&tr[x].r==r){Modify(x);return;}
	int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
	down(x);
	if(r<=mid)modify(lc,l,r);
	else if(l>mid)modify(rc,l,r);
	else modify(lc,l,mid),modify(rc,mid+1,r);
	up(x);
}
bool query(int x,int l,int r)
{
	if(l>r)return true;
	if(tr[x].l==l&&tr[x].r==r)return tr[x].c;
	int mid=tr[x].l+tr[x].r>>1,lc=tr[x].lc,rc=tr[x].rc;
	down(x);
	if(r<=mid)return query(lc,l,r);
	if(l>mid)return query(rc,l,r);
	return(query(lc,l,mid)&query(rc,mid+1,r));
}
struct Opt{int type,x,y;}Q[Maxn];int ans[Maxn],la=0;
struct edge{int x,y;edge(int _x=0,int _y=0){x=_x,y=_y;}}rest[Maxn],tmp[Maxn];int lr=0,lt=0;
bool operator<(edge a,edge b)
{
	if(a.x!=b.x)return a.x<b.x;
	return a.y<b.y;
}
priority_queue<edge>q1,q2;
void dfs1(int x,int ff)
{
	fa[x]=ff;dep[x]=dep[ff]+1;son[x]=0;sz[x]=1;
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y==ff)continue;
		dfs1(y,x);sz[x]+=sz[y];
		if(sz[y]>sz[son[x]])son[x]=y;
	}
}
void dfs2(int x,int Top)
{
	top[x]=Top;dfn[x]=++DFN;
	if(son[x])dfs2(son[x],Top);
	for(int i=last[x];i;i=e[i].next)
	{
		int y=e[i].y;
		if(y==son[x]||y==fa[x])continue;
		dfs2(y,y);
	}
}
bool w(int x,int y,int o)
{
	int tx=top[x],ty=top[y];bool re=true;
	while(tx!=ty)
	{
		if(dep[tx]<dep[ty])swap(x,y),swap(tx,ty);
		if(o==0)modify(1,dfn[tx],dfn[x]);
		else re&=query(1,dfn[tx],dfn[x]);
		x=fa[tx];tx=top[x];
	}
	if(dep[x]<dep[y])swap(x,y);
	if(o==0)modify(1,dfn[son[y]],dfn[x]);
	else re&=query(1,dfn[son[y]],dfn[x]);
	return re;
}
int main()
{
	n=read(),m=read(),q=read();dfn[0]=inf;
	for(int i=1;i<=n;i++)rt[i]=i;
	for(int i=1;i<=m;i++)
	{
		int x=read(),y=read();
		if(x>y)swap(x,y);q1.push(edge(x,y));
	}
	for(int i=1;i<=q;i++)
	{
		char op[2];
		scanf("%s",op);
		if(op[0]=='P')Q[i].type=1;else Q[i].type=0;
		int x=read(),y=read();
		if(x>y)swap(x,y);Q[i].x=x,Q[i].y=y;
		if(Q[i].type==0)q2.push(edge(x,y));
	}
	while(!q1.empty())
	{
		edge t1=q1.top();q1.pop();
		if(q2.empty())rest[++lr]=t1;
		else
		{
			edge t2=q2.top();
			if(t1.x==t2.x&&t1.y==t2.y)q2.pop();
			else rest[++lr]=t1;
		}
	}
	for(int i=1;i<=lr;i++)
	{
		int fx=findrt(rest[i].x),fy=findrt(rest[i].y);
		if(fx==fy){tmp[++lt]=rest[i];continue;}
		rt[fx]=fy;ins(rest[i].x,rest[i].y),ins(rest[i].y,rest[i].x);
	}
	for(int i=1;i<=n;i++)_rt[i]=rt[i];
	for(int i=q;i;i--)
	if(Q[i].type==0)
	{
		int fx=findrt(Q[i].x),fy=findrt(Q[i].y);
		if(fx==fy)continue;
		rt[fx]=fy;ins(Q[i].x,Q[i].y),ins(Q[i].y,Q[i].x);
	}
	int root=n+1;
	for(int i=1;i<=n;i++)
	{
		int t=findrt(i);
		if(!mark[t])ins(root,t),mark[t]=true;
	}
	dep[0]=-1;dfs1(root,0);dfs2(root,root);
	for(int i=1;i<=n;i++)rt[i]=_rt[i];
	build(1,DFN);
	for(int i=1;i<=lt;i++)w(tmp[i].x,tmp[i].y,0);
	for(int i=q;i;i--)
	{
		int fx=findrt(Q[i].x),fy=findrt(Q[i].y);
		if(Q[i].type==1)
		{
			if(fx!=fy)ans[++la]=0;
			else ans[++la]=w(Q[i].x,Q[i].y,1);
		}
		else
		{
			if(fx!=fy)rt[fx]=fy;
			else w(Q[i].x,Q[i].y,0);
		}
	}
	for(int i=la;i;i--)puts(ans[i]==1?"Yes":"No");
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值