N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。
K行每行一个整数代表该组询问的联通块个数。
对于100%的数据,1≤N、M、K≤200,000。
2016.2.26提高时限至60s
题解
这道题是一道思路好题(废话)
我们可以维护每条边关于加入时间的最大生成树
然后如果弹出一条边,记录这条边被谁弹出
然后显然对于区间 [l,r] ti 大于 r 的边一定不会被删除
并且所有 ti 小于等于 r 的边一定被删除
因为 ti 小于等于 r 的边一定在一个所有边编号都小于等于 r 并且都大
所以这段区间的答案为n-区间内大于r的数的个数
可持久化权值线段树维护下
代码
//by 减维
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<bitset>
#include<set>
#include<cmath>
#include<vector>
#include<set>
#include<map>
#include<ctime>
#include<algorithm>
#define ll long long
#define il inline
#define rg register
#define db double
#define inf (1<<30)
#define maxn 400005
#define mpr make_pair
#define eps 1e-8
using namespace std;
inline int read()
{
int ret=0;bool fla=0;char ch=getchar();
while((ch<'0'||ch>'9')&&ch!='-')ch=getchar();
if(ch=='-'){fla=1;ch=getchar();}
while(ch>='0'&&ch<='9'){ret=ret*10+ch-'0';ch=getchar();}
return fla?-ret:ret;
}
struct edge{
int x,y;
}e[maxn];
struct tree{
int l,r,v;
}t[maxn<<5];
int n,m,q,tt,ans,cnt,rt[maxn],fa[maxn],son[maxn][2],val[maxn],rev[maxn],pos[maxn],tim[maxn];
il bool pdp(int x){return son[fa[x]][1]==x;}
il bool isrt(int x){return son[fa[x]][0]!=x&&son[fa[x]][1]!=x;}
il void rever(int x){rev[x]^=1;swap(son[x][0],son[x][1]);}
il void upda(int x)
{
pos[x]=x;
if(son[x][0]&&val[pos[son[x][0]]]<val[pos[x]]) pos[x]=pos[son[x][0]];
if(son[x][1]&&val[pos[son[x][1]]]<val[pos[x]]) pos[x]=pos[son[x][1]];
}
il void pdn(int x)
{
if(rev[x])
{
if(son[x][0]) rever(son[x][0]);
if(son[x][1]) rever(son[x][1]);
rev[x]=0;
}
}
void pd(int x){if(!isrt(x)) pd(fa[x]);pdn(x);}
il void rot(int x)
{
int f=fa[x],g=fa[f],o=pdp(x);
if(!isrt(f)) son[g][pdp(f)]=x;fa[x]=g;
son[f][o]=son[x][!o];fa[son[f][o]]=f;
son[x][!o]=f;fa[f]=x;
upda(f),upda(x);
}
il void splay(int x)
{
pd(x);
for(;!isrt(x);rot(x))
if(!isrt(fa[x])) rot(pdp(fa[x])==pdp(x)?fa[x]:x);
}
il void acc(int x)
{
for(int y=0;x;y=x,x=fa[x])
splay(x),son[x][1]=y,upda(x);
}
il int find(int x)
{
acc(x);splay(x);
while(son[x][0]) pd(x),x=son[x][0];
return x;
}
il void bert(int x){acc(x);splay(x);rever(x);}
il void spli(int x,int y){bert(x);acc(y);splay(y);}
il void cut(int x,int y){spli(x,y);fa[x]=son[y][0]=0;upda(y);}
il void link(int x,int y,int z)
{
if(find(x)==find(y))
{
spli(x,y);
int aa=pos[y];//printf("%d\n",aa);
cut(e[aa-n].x,aa);cut(e[aa-n].y,aa);
tim[aa-n]=z-n;
}
bert(x);fa[x]=z;
bert(y);fa[y]=z;
}
void upd(int x)
{
t[x].v=t[t[x].l].v+t[t[x].r].v;
}
void build(int l,int r,int las,int &now,int v)
{
now=++cnt;t[now]=t[las];t[now].v++;
if(l==r)return ;
int mid=(l+r)>>1;
if(v<=mid) build(l,mid,t[las].l,t[now].l,v);
else build(mid+1,r,t[las].r,t[now].r,v);
}
int query(int l,int r,int x,int y,int v)
{
if(l==v) return t[y].v-t[x].v;
int mid=(l+r)>>1;
if(v<=mid) return query(l,mid,t[x].l,t[y].l,v)+t[t[y].r].v-t[t[x].r].v;
else return query(mid+1,r,t[x].r,t[y].r,v);
}
int main()
{
n=read(),m=read();q=read(),tt=read();
for(int i=0;i<=n;++i) val[i]=inf;
for(int i=1;i<=m;++i)
{
e[i].x=read(),e[i].y=read();
val[n+i]=i;tim[i]=m+1;
if(e[i].x==e[i].y){tim[i]=i;continue;}
link(e[i].x,e[i].y,n+i);
}
for(int i=1;i<=m;++i)
build(0,m+1,rt[i-1],rt[i],tim[i]);
for(int i=1,l,r;i<=q;++i)
{
l=read(),r=read();
if(tt) l^=ans,r^=ans;
printf("%d\n",ans=n-query(0,m+1,rt[l-1],rt[r],r+1));
}
return 0;
}
本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系我们删除。