您的位置:首页 > 其它

BZOJ3514: Codechef MARCH14 GERALD07加强版

2017-02-22 16:22 141 查看
传送门

闲来无事练两个板子。

一个思路上的trick就是判定边对是否更新连通块数量的贡献,如果一条边将一个子图连成环,那么这个是对连通块数量的减少没有贡献的。

考虑用LCT维护联通与环即可,我们预处理出每条边对应的最早的能连成环的边,对于一个区间$[L,R]$,如果最早能形成环的边在这个区间之前,那么就可以认为这个边是对答案有贡献的,主席树维护即可。

另外需要注意自环的情况。

//BZOJ 3514
//by Cydiater
//2017.2.22
#include <iostream>
#include <queue>
#include <map>
#include <cstring>
#include <string>
#include <ctime>
#include <cmath>
#include <iomanip>
#include <cstdlib>
#include <cstdio>
#include <algorithm>
#include <bitset>
#include <set>
#include <complex>
using namespace std;
#define ll long long
#define up(i,j,n)	for(int i=j;i<=n;i++)
#define down(i,j,n)	for(int i=j;i>=n;i--)
#define cmax(a,b)	a=max(a,b)
#define cmin(a,b)	a=min(a,b)
#define pii		pair<int,int>
#define fi 		first
#define se 		second
#define mp		make_pair
const int MAXN=5e5+5;
const int oo=0x3f3f3f3f;
inline int read(){
char ch=getchar();int x=0,f=1;
while(ch>'9'||ch<'0'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int N,M,K,type,fri[MAXN];
pii E[MAXN];
namespace LCT{
struct tr{
int son[2],fa,tag,id,val;
tr(){val=oo;}
void clear(){son[0]=son[1]=fa=tag=id=0;val=oo;}
}t[MAXN];
inline int isrt(int k){return t[t[k].fa].son[0]!=k&&t[t[k].fa].son[1]!=k;}
inline int get(int k){return t[t[k].fa].son[1]==k;}
inline void rev(int k){
if(!k)return;
swap(t[k].son[0],t[k].son[1]);
t[k].tag^=1;
}
inline void reload(int k){
if(!k)return;
t[k].id=k;
int s1=t[k].son[0],s2=t[k].son[1];
int i1=t[s1].id,i2=t[s2].id;
if(t[i1].val<t[t[k].id].val)t[k].id=i1;
if(t[i2].val<t[t[k].id].val)t[k].id=i2;
}
inline void Pushdown(int k){
if(!k)return;
if(t[k].tag){
rev(t[k].son[0]);rev(t[k].son[1]);
t[k].tag^=1;
}
}
inline void rotate(int k){
int old=t[k].fa,oldf=t[old].fa,which=get(k);
if(!isrt(old))t[oldf].son[old==t[oldf].son[1]]=k;
t[old].son[which]=t[k].son[which^1];t[t[old].son[which]].fa=old;
t[k].son[which^1]=old;t[old].fa=k;t[k].fa=oldf;t[0].clear();
reload(old);reload(k);
}
int stack[MAXN],top=0;
inline void splay(int k){
top=0;stack[++top]=k;
for(int tmp=k;!isrt(tmp);tmp=t[tmp].fa)stack[++top]=t[tmp].fa;
while(top)Pushdown(stack[top--]);
while(!isrt(k)){
int old=t[k].fa;
if(!isrt(old))rotate(get(old)==get(k)?old:k);
rotate(k);
}
}
void access(int k){
int tmp=0;
while(k){
splay(k);t[k].son[1]=tmp;
reload(k);tmp=k;k=t[k].fa;
}
}
void mrt(int k){
access(k);splay(k);rev(k);
}
int grt(int k){
access(k);splay(k);
while(t[k].son[0])k=t[k].son[0];
return k;
}
void Link(int x,int y){
mrt(x);t[x].fa=y;
}
void Cut(int x,int y){
mrt(x);access(y);splay(y);t[y].son[0]=t[x].fa=0;
reload(y);
}
int res(int x,int y){
mrt(x);access(y);splay(y);
return t[y].id;
}
void Go(){
up(i,1,M){
int x=E[i].fi,y=E[i].se;
if(x==y)continue;
if(grt(x)==grt(y)){
int id=res(x,y)-N;
fri[i]=id;
int tx=E[id].fi,ty=E[id].se;
Cut(tx,id+N);Cut(ty,id+N);
}
int id=i+N;
t[id].val=i;t[id].id=id;
Link(x,id);Link(y,id);
}
}
}
namespace ChairManTree{
int cnt=0,root[MAXN];
struct tree{
int son[2],siz;
}t[MAXN<<3];
int NewNode(int s1,int s2,int siz){
t[++cnt].son[0]=s1;t[cnt].son[1]=s2;
t[cnt].siz=siz;
return cnt;
}
void Build(int L,int R,int &k,int lr,int val){
k=NewNode(t[lr].son[0],t[lr].son[1],t[lr].siz+1);
if(L==R)return;
int mid=(L+R)>>1;
if(val<=mid)	Build(L,mid,t[k].son[0],t[lr].son[0],val);
else		Build(mid+1,R,t[k].son[1],t[lr].son[1],val);
}
int Query(int L,int R,int r1,int r2,int LIM){
int lsiz=t[t[r2].son[0]].siz-t[t[r1].son[0]].siz;
int siz=t[r2].siz-t[r1].siz,mid=(L+R)>>1;
if(L==R)		return siz;
if(mid>LIM)		return Query(L,mid,t[r1].son[0],t[r2].son[0],LIM);
else if(R<=LIM)		return siz;
else if(mid==LIM)	return lsiz;
else if(mid+1<=LIM)	return lsiz+Query(mid+1,R,t[r1].son[1],t[r2].son[1],LIM);
}
}
int last=0,L,R;
namespace solution{
void Prepare(){
N=read();M=read();K=read();type=read();
up(i,1,M){
int x=read(),y=read();
E[i]=mp(x,y);if(x==y)fri[i]=M+1;
}
LCT::Go();
}
void Solve(){
//up(i,1,M)printf("%d ",fri[i]);puts("");
using namespace ChairManTree;
up(i,1,M)Build(0,M+1,root[i],root[i-1],fri[i]);
while(K--){
L=read();R=read();
if(type){L^=last;R^=last;}
if(L>R)swap(L,R);
printf("%d\n",last=max(N-Query(0,M+1,root[L-1],root[R],L-1),1));
}
}
}
int main(){
//freopen("input.in","r",stdin);
using namespace solution;
Prepare();
Solve();
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: