【LCT+主席树】BZOJ3514 Codechef MARCH14 GERALD07加强版
3514: Codechef MARCH14 GERALD07加强版
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 2023 Solved: 778
[Submit][Status][Discuss]
Description
N个点M条边的无向图,询问保留图中编号在[l,r]的边的时候图中的联通块个数。
Input
第一行四个整数N、M、K、type,代表点数、边数、询问数以及询问是否加密。
接下来M行,代表图中的每条边。
接下来K行,每行两个整数L、R代表一组询问。对于type=0的测试点,读入的L和R即为询问的L、R;对于type=1的测试点,每组询问的L、R应为L xor lastans和R xor lastans。
Output
K行每行一个整数代表该组询问的联通块个数。
Sample Input
3 5 4 0
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
1 3
1 2
2 1
3 2
2 2
2 3
1 5
5 5
1 2
Sample Output
2
1
3
1
1
3
1
HINT
对于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; }