bzoj3514
对于这道题,想都没想,毫不犹豫的看了题解,这样就变成了只是练习写代码,没有思考。觉得自己这样不好。必须改。
参考题解:
http://wenku.baidu.com/view/a611cec4dd3383c4bb4cd2d8.html
http://blog.csdn.net/jiangyuze831/article/details/41694643
简单证明:
求(L,R)的联通块个数,是相当于往一个只有点1到n的,没有边的图中添加边(L,R),假设边X ,L<=X<=R,X添加后,可能会少一个联通块,也可能不回少,在于它所连接的那两个点是不是已经是联通的,但是这个联通是要求用(L,X-1)这些边造成的联通,所以要始终维护一棵树,(维护一棵树的意义就是,不连通的两个点因为加入某条边Y联通后,就一直处于联通装态,不会断开,同时维护最大生成树(每条边的编号是它的权值),使得树又是用离Y最近的边构成的),因此,在加入X时,X连接的两个点,有三种情况:
1.两点不连通,既然(1,X-1)都无法是这两个点联通,那么(L,X-1)也无法是这两个点联通。加入X后,会使得联通块个数减少1。
2.两点联通,且两点之间路径上的最小值小于L。如果存在(L,X-1)使得这两个点联通的话,那么此时最小值就一定大于等于L,(L,X-1)无法使得这两个点联通。加入X后,会联通块个数减少1。
3.两点联通,且两点之间路径上的最大值大于等于L,说明(L,X-1)可以使得这两个点联通,加入X后,不会使得联通块个数减少.
4.X链接的两点相同,那么此时联通块个数不会减少。
综上所述,用lct维护一棵最大生成树,数组num[i] 记载,加入某条边 i 时,两点不连通,则num[i]=0,如果两点联通,则记录路径上最小权值,特别的,如果一条边的两点相同时,num[i]=n+1(n是边的个数)。
代码:
#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
#define N 200010
#define INF 0x3f3f3f3f
struct node{
node *fa;
node *ch[2];
int rev;
int val;
int minval;
int valnum;
int minvalnum;//用来记录以某个点为根节点的子树的最大值,而不是左子树的最大值,否则可能会错(不知道有没有严格的证明来证明绝对不会出错?所以这里只写可能会出错)
int from;//涉及到维护生成树时,要有from和to
int to;
int init(int tempval,int tempvalnum,int tempfrom,int tempto){
ch[0]=ch[1]=fa=NULL;
rev=0;
val=tempval;
minval=val;
valnum=tempvalnum;
minvalnum=valnum;
from=tempfrom;
to=tempto;
}
bool isroot(){
/*if(this==NULL){//这个输出了
printf("hahaha\n");
}*/
return fa==NULL||(fa->ch[0]!=this&&fa->ch[1]!=this);
}
void fswitch(){
rev^=1;
swap(ch[0],ch[1]);
}
void push_down(){
if(rev){
if(ch[0]){
ch[0]->fswitch();
}
if(ch[1]){
ch[1]->fswitch();
}
rev=0;
}
return;
}
void go(){
/*if(this==NULL){//这里输出了
printf("wo shi da hao ren");
}*/
if(!isroot()){
fa->go();
}
push_down();
return;
}
int dir(){
return fa->ch[1]==this?1:0;
}
void setedge(int d,node *another){
ch[d]=another;
if(another){
another->fa=this;//这里是this,不是NULL
}
return;
}
void push_up(){
minvalnum=valnum;
minval=val;
if(ch[0]){
if(minvalnum>ch[0]->minvalnum){
minval=ch[0]->minval;
minvalnum=ch[0]->minvalnum;
}
}
if(ch[1]){
if(minvalnum>ch[1]->minvalnum){
minval=ch[1]->minval;
minvalnum=ch[1]->minvalnum;
}
}
return;
}
void rot(){
int d=dir();
node *tempfafa=fa->fa;
if(!(fa->isroot())){
tempfafa->ch[fa->dir()]=this;
}
fa->setedge(d,ch[!d]);
setedge(!d,fa);
fa=tempfafa;
ch[!d]->push_up();
return;
}
void splay(){
/*if(this==NULL){
printf("wo shi da hao ren");//这里输出了
}*/
go();
while(!isroot()){
if(!(fa->isroot())){
dir()==fa->dir()?fa->rot():rot();
}
rot();
}
push_up();
return;
}
void access(){
for(node *p=this,*q=NULL;p!=NULL;q=p,p=p->fa){
p->splay();
p->setedge(1,q);
p->push_up();
}
/*if(this==NULL){
printf("wo shi da hao ren");//这里输出了
}*/
splay();
return;
}
void make_root(){
/*if(this==NULL){//这里输出了
printf("wo sh da hao ren");
}*/
access();
fswitch();
}
void cut(node *another){
/*if(another==NULL){//这里输出了
printf("wo shi da hao ren");
}*/
another->make_root();
access();
ch[0]->fa=NULL;
ch[0]=NULL;
push_up();
return;
}
void link(node *another){
another->make_root();
another->fa=this;
return;
}
node *find_root(){
node *temp=this;
while(temp->fa){//这里出现了死循环,说明某个temp->fa==temp,应该是前面lct的基本操作出了问题
/*if(temp==temp->fa){
printf("wo shi da hao ren");
}*/
temp=temp->fa;
}
return temp;
}
bool islink(node *another){
return find_root()==another->find_root()?true:false;
}
int query(node *another){
another->make_root();
access();
return minval;
}
};
node *tree[2*N],pool[2*N];
int num[N];
int Tree[N];
int c[30*N],lson[30*N],rson[30*N];
int cou;//记得初始化
int m;
void addedge(int x,int y,int id){
if(x==y){
num[id]=m+1;//注意这里的return必须添加
return;
}
if(tree[x]->islink(tree[y])){
int tempval=tree[x]->query(tree[y]);
if(tree[tempval]->valnum<id){
num[id]=tree[tempval]->valnum;
tree[tempval]->cut(tree[tree[tempval]->from]);
tree[tempval]->cut(tree[tree[tempval]->to]);
tree[tempval]->init(tempval,id,x,y);
tree[tempval]->link(tree[x]);
tree[tempval]->link(tree[y]);
}
}
else{
tree[++cou]=&(pool[cou]);
tree[cou]->init(cou,id,x,y);
tree[cou]->link(tree[x]);
tree[cou]->link(tree[y]);
num[id]=0;
}
return;
}
int build(int l,int r){
int root=cou++;
c[root]=0;
if(l!=r){
int middle=(l+r)>>1;
lson[root]=build(l,middle);
rson[root]=build(middle+1,r);
}
return root;
}
int insert(int froroot,int x){
int root=cou++,temproot=root;
int l=0,r=m+1;
c[temproot]=c[froroot]+1;
while(l<r){
int middle=(l+r)>>1;
if(x<=middle){
r=middle;
lson[temproot]=cou++;
rson[temproot]=rson[froroot];
temproot=lson[temproot];
froroot=lson[froroot];
}
else{
l=middle+1;
lson[temproot]=lson[froroot];
rson[temproot]=cou++;
temproot=rson[temproot];
froroot=rson[froroot];
}
c[temproot]=c[froroot]+1;
}
return root;
}
int query(int root,int l,int r,int x){
if(l==r){
if(l<x){
return c[root];
}
else{
return 0;
}
}
else{
int middle=(l+r)>>1;
if(x<=middle){
return query(lson[root],l,middle,x);
}
else{
return c[lson[root]]+query(rson[root],middle+1,r,x);
}
}
}
int main(){
int n,k,type;
int a,b;
scanf("%d%d%d%d",&n,&m,&k,&type);
for(int i=1;i<=n;i++){
tree[i]=&(pool[i]);
tree[i]->init(i,INF,-1,-1);
}
cou=n;//这个要放对位置,否则会re
for(int i=1;i<=m;i++){
scanf("%d%d",&a,&b);
addedge(a,b,i);
}
Tree[0]=build(0,m+1);
for(int i=1;i<=m;i++){
Tree[i]=insert(Tree[i-1],num[i]);
}
if(type){
int lastans=0;
for(int i=0;i<k;i++){
scanf("%d%d",&a,&b);
a=a^lastans;
b=b^lastans;
lastans=n-query(Tree[b],0,m+1,a)+query(Tree[a-1],0,m+1,a);
printf("%d\n",lastans);
}
}
else{
for(int i=0;i<k;i++){
scanf("%d%d",&a,&b);
printf("%d\n",n-query(Tree[b],0,m+1,a)+query(Tree[a-1],0,m+1,a));
}
}
return 0;
}

浙公网安备 33010602011771号