BZOJ3514: Codechef MARCH14 GERALD07加强版
题解: 很久以前写的一道题 刚开始找不到切入点 我们这样考虑吧 对于每个查询 我们查询当前加入[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