题解: 很久以前写的一道题 刚开始找不到切入点 我们这样考虑吧 对于每个查询 我们查询当前加入[l,r]边的联通快的个数 那么我们从联通块的本身出发 当前的联通块的个数应该等于n-关键路径的条数 关键路径等于总路径-无用路径的条数 那么我们怎么去判断一条路径是无用的呢 当且仅当 你加入这条边形成环的最小标号是无用路径 然后主席数维护区间无用路径的条数即可
/**************************************************************
Problem: 3514
User: c20161007
Language: C++
Result: Accepted
Time:37272 ms
Memory:134500 kb
****************************************************************/
#include <bits/stdc++.h>
#define ll long long
#define pii pair<int,int>
const int MAXN=4e5+10;
const int inf=1e9+10;
using namespace std;
ll readll(){
ll x=0,f=1;char ch=getchar();
while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}
return x*f;
}
int readint(){
int x=0,f=1;char ch=getchar();
while(!isdigit(ch)){if(ch=='-')f=-1;ch=getchar();}
while(isdigit(ch))x=x*10+ch-'0',ch=getchar();
return f*x;
}
int minn[MAXN],ch[MAXN][2],key[MAXN],pre[MAXN],res[MAXN],fa[MAXN],n,m,q,type,cnt;
int root[MAXN];
bool rt[MAXN];
void Treavel(int x)
{
if(x)
{
// cout<<x<<endl;
Treavel(ch[x][0]);
printf("结点%2d:左儿子 %2d 右儿子 %2d 父结点 %2d 最小值 %2d,key=%2d\n",x,ch[x][0],ch[x][1],pre[x],minn[x],key[x]);
Treavel(ch[x][1]);
}
}
void debug(int rp)
{
printf("root:%d\n",rp);
Treavel(rp);
}
void reverse(int r){
if(!r) return ;
swap(ch[r][0],ch[r][1]);
res[r]^=1;
}
void push(int r){
if(res[r]){
reverse(ch[r][0]);
reverse(ch[r][1]);
res[r]^=1;
}
}
void up(int r){
if(!r) return ;
minn[r]=r;
if(key[minn[ch[r][0]]]<key[minn[r]]) minn[r]=minn[ch[r][0]];
if(key[minn[ch[r][1]]]<key[minn[r]]) minn[r]=minn[ch[r][1]];
}
void P(int r){
if(!rt[r]) P(pre[r]);
push(r);
}
void rotate(int x,int kind){
int y=pre[x];
pre[ch[x][kind]]=y;ch[y][!kind]=ch[x][kind];
if(rt[y]) rt[y]=0,rt[x]=1;
else ch[pre[y]][ch[pre[y]][1]==y]=x;
pre[x]=pre[y];ch[x][kind]=y;pre[y]=x;
up(y);
}
void splay(int x){
P(x);
while(!rt[x]){
if(rt[pre[x]]) rotate(x,ch[pre[x]][0]==x);
else{
int y=pre[x];int kind=ch[pre[y]][0]==y;
if(ch[y][kind]==x) rotate(x,!kind),rotate(x,kind);
else rotate(y,kind),rotate(x,kind);
}
}
up(x);
}
void access(int x){
int y=0;
while(x){
splay(x);
if(ch[x][1]) rt[ch[x][1]]=1,pre[ch[x][1]]=x;
ch[x][1]=y;
up(x);
if(y) rt[y]=0;
y=x;x=pre[x];
}
}
void mroot(int u){
access(u);splay(u);
reverse(u);
}
bool pd(int u,int v){
while(pre[u]) u=pre[u];
while(pre[v]) v=pre[v];
return u==v;
}
void Link(int u,int v){
mroot(u);pre[u]=v;
}
void destory(int u,int v){
mroot(u);access(v);splay(v);
rt[u]=rt[v]=1;pre[u]=pre[v]=0;ch[v][0]=0;
up(v);up(u);
}
int querty(int u,int v){
mroot(u);access(v);splay(v);
// debug(v);
//cout<<u<<" "<<v<<" "<<minn[v]<<endl;
return minn[v];
}
void newnode(int t){
rt[t]=1;res[t]=pre[t]=ch[t][0]=ch[t][1]=0;minn[t]=t;key[t]=inf;
}
pii w[MAXN];
typedef struct node{
int l,r,sum;
}node;
node d[25*MAXN];
void update(int &x,int y,int l,int r,int t){
cnt++;x=cnt;d[x]=d[y];d[x].sum--;
//cout<<l<<" "<<r<<" "<<t<<" "<<d[x].sum<<endl;
if(l==r) return ;
int mid=(l+r)>>1;
if(t<=mid) update(d[x].l,d[y].l,l,mid,t);
else update(d[x].r,d[y].r,mid+1,r,t);
}
int ans;
void querty1(int x,int l,int r,int ql,int qr){
if(ql<=l&&r<=qr){
//cout<<l<<" "<<r<<" "<<d[x].sum<<endl;
ans+=d[x].sum;
return ;
}
int mid=(l+r)>>1;
if(ql<=mid) querty1(d[x].l,l,mid,ql,qr);
if(qr>mid) querty1(d[x].r,mid+1,r,ql,qr);
}
int main(){
ios::sync_with_stdio(false);
n=readint();m=readint();q=readint();type=readint();
key[0]=inf;cnt=0;
for(int i=1;i<=n+m;i++) newnode(i);
int u,v;
for(int i=1;i<=m;i++){
u=readint();v=readint();w[i].first=u;w[i].second=v;
if(u==v){
fa[i]=i;continue;
}
//cout<<pd(u,v)<<endl;
if(!pd(u,v)){
fa[i]=0;key[i+n]=i;Link(u,i+n);Link(v,i+n);
//cout<<i<<" "<<key[i+n]<<endl;
}
else{
int t=querty(u,v);int tt=key[t];
//cout<<t<<" "<<tt<<endl;
fa[i]=tt;
destory(t,w[tt].first);destory(t,w[tt].second);
key[i+n]=i;
Link(i+n,u);Link(i+n,v);
}
}
//cout<<"sb"<<endl;
// for(int i=1;i<=m;i++) cout<<fa[i]<<" ";
// cout<<endl;
for(int i=1;i<=m;i++){
if(!fa[i]){
root[i]=root[i-1];continue;
}
//cout<<"sb"<<endl;
update(root[i],root[i-1],1,m,fa[i]);
//cout<<"sb"<<endl;
}
int Lans=0;int l,r;
for(int i=1;i<=q;i++){
l=readint();r=readint();
if(type==1) l^=Lans,r^=Lans;
if(l>r) swap(l,r);
ans=0;querty1(root[r],1,m,l,r);
//cout<<ans<<endl;
Lans=n-((r-l+1)+ans);
printf("%d\n",Lans);
}
return 0;
}
3514: Codechef MARCH14 GERALD07加强版
Time Limit: 60 Sec Memory Limit: 256 MBSubmit: 2363 Solved: 907
[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