您的位置:首页 > 其它

[BZOJ3514]Codechef MARCH14 GERALD07加强版

2018-03-11 16:14 288 查看
首先一条一条把边加入图中,维护一棵生成树

假设当前要加$(x,y)$,如果$x$和$y$不连通,直接加边,否则把树上$x\rightarrow y$最早加入的边删除并加入$(x,y)$,记被第$i$条边挤掉的边为$drop_i$,这个过程可以用lct维护

对于每个询问$[l,r]$,考虑轮流加边$i\in[l,r]$把图连起来,如果$drop_i\geq l$,那么它是某个环中的一条边,对答案没有贡献,否则它连接了两个联通块,答案$-1$,所以答案就是$n-\sum\limits_{i=l}^r\left[drop_i\lt l\right]$,直接用可持久化线段树外层$drop$内层下标统计即可

#include<stdio.h>
#include<algorithm>
using namespace std;
int fa[400010],ch[400010][2],r[400010],id[400010],mn[400010];
#define ls ch[x][0]
#define rs ch[x][1]
void pushup(int x){
mn[x]=x;
if(ls&&id[mn[ls]]<id[mn[x]])mn[x]=mn[ls];
if(rs&&id[mn[rs]]<id[mn[x]])mn[x]=mn[rs];
}
void rev(int x){
r[x]^=1;
swap(ls,rs);
}
void pushdown(int x){
if(r[x]){
if(ls)rev(ls);
if(rs)rev(rs);
r[x]=0;
}
}
void rot(int x){
int y,z,f,b;
y=fa[x];
z=fa[y];
f=ch[y][0]==x;
b=ch[x][f];
fa[x]=z;
fa[y]=x;
if(b)fa[b]=y;
ch[x][f]=y;
ch[y][f^1]=b;
if(ch[z][0]==y)ch[z][0]=x;
if(ch[z][1]==y)ch[z][1]=x;
pushup(y);
pushup(x);
}
bool isrt(int x){return ch[fa[x]][0]!=x&&ch[fa[x]][1]!=x;}
void gao(int x){
if(!isrt(x))gao(fa[x]);
pushdown(x);
}
void splay(int x){
int y,z;
gao(x);
while(!isrt(x)){
y=fa[x];
z=fa[y];
if(!isrt(y))rot((ch[z][0]==y&&ch[y][0]==x)||(ch[z][1]==y&&ch[y][1]==x)?y:x);
rot(x);
}
}
void access(int x){
int y=0;
while(x){
splay(x);
rs=y;
pushup(x);
y=x;
x=fa[x];
}
}
void makert(int x){
access(x);
splay(x);
rev(x);
}
void link(int x,int y){
makert(x);
fa[x]=y;
}
int cutmin(int x,int y){
makert(x);
access(y);
splay(y);
x=mn[y];
splay(x);
fa[ls]=fa[rs]=0;
ls=rs=0;
mn[x]=x;
return x;
}
struct dsu{
int fa[200010];
void pre(int n){
for(int i=1;i<=n;i++)fa[i]=i;
}
int get(int x){return(x==fa[x])?x:(fa[x]=get(fa[x]));}
void join(int x,int y){fa[get(x)]=get(y);}
}st;
struct num{
int x,drop;
}d[200010];
bool operator<(num a,num b){return a.drop<b.drop;}
struct seg{
int l,r,siz;
}t[4000010];
int rt[200010],drop[200010],M;
void insert(int pr,int&nr,int p,int l,int r){
nr=++M;
t[nr]=t[pr];
t[nr].siz++;
if(l==r)return;
int mid=(l+r)>>1;
if(p<=mid)
insert(t[pr].l,t[nr].l,p,l,mid);
else
insert(t[pr].r,t[nr].r,p,mid+1,r);
}
int query(int L,int R,int l,int r,int x){
if(x==0)return 0;
if(L<=l&&r<=R)return t[x].siz;
int mid=(l+r)>>1,ans=0;
if(L<=mid)ans+=query(L,R,l,mid,t[x].l);
if(mid<R)ans+=query(L,R,mid+1,r,t[x].r);
return ans;
}
int main(){
int n,m,k,type,i,j,x,y,M,las;
scanf("%d%d%d%d",&n,&m,&k,&type);
st.pre(n);
for(i=1;i<=n;i++){
id[i]=1000000000;
mn[i]=i;
}
M=n;
for(i=1;i<=m;i++){
d[i].x=i;
scanf("%d%d",&x,&y);
if(x==y){
drop[i]=d[i].drop=i;
continue;
}
if(st.get(x)==st.get(y)){
las=cutmin(x,y);
drop[i]=d[i].drop=id[las];
id[las]=i;
link(x,las);
link(las,y);
}else{
st.join(x,y);
M++;
mn[M]=M;
id[M]=i;
link(x,M);
link(M,y);
}
}
sort(d+1,d+m+1);
for(i=1;i<=m;i++){
if(i!=1){
for(j=d[i-1].drop+1;j<=d[i].drop;j++)rt[j]=rt[j-1];
}
insert(rt[d[i].drop],rt[d[i].drop],d[i].x,1,m);
}
for(i=d[m].drop;i<m;i++)rt[i+1]=rt[i];
las=0;
while(k--){
scanf("%d%d",&x,&y);
if(type){
x^=las;
y^=las;
}
las=n-query(x,y,1,m,rt[x-1]);
printf("%d\n",las);
}
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: