在西塘的大部分时间都呆在书店了,一个人出去逛没什么意思啊...
学子讲坛终于弄完了,可以开始除草了...(大家比我想像的有童心的样子...
codechef GERALD07
n个点m条边,q个询问,每次询问l,r的边会形成多少联通块
有用的边只有n-1条,即生成树边,因为一条树边就会减少一个联通块,但显然生成树不同,树边也不同,考虑离线处理询问,按r排序,维护一棵1~r的边组成的生成树,每加入一条边,就把环上出现的最早的边给环切掉,因为这样处理询问,都是右端点固定的,[li,r],那么树边越靠右,能处理的区间就越多,那么当所有树边都尽可能靠右的时候,只要知道li~r中有多少树边就可以知道联通块个数
update5.19:zkw线段树千万记得清空,最近老错
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
const int oo=1073741819;
using namespace std;
struct Ques{
int l,r,i;
}Q[250000];
struct Line{
int l,r;
}L[250000];
int l[2000000],r[2000000],rt[2000000],w[2000000],M[2000000],sw[2000000];
int sum[2000000],Ans[2000000];
int n,m,q,m1;
void origin()
{
for (int i=1;i<=m1+m1;i++) sum[i]=0;
for (m1=1;m1<=m+2;m1<<=1) ;
w[0]=oo;
for (int i=1;i<=n;i++) {
l[i]=r[i]=rt[i]=sw[i]=0;
w[i]=oo,M[i]=i;
}
for (int i=n+1;i<=n+m;i++) {
l[i]=r[i]=rt[i]=sw[i]=0;
w[i]=i-n,M[i]=i;
}
}
void change(int x,int w)
{
if (!x) return ;
sum[x+=m1]=w;
for (x>>=1;x;x>>=1)
sum[x]=sum[x<<1]+sum[(x<<1)+1];
}
int ask(int l,int r)
{
l+=m1-1,r+=m1+1;
int ans=0;
for (;!((l^r)==1);l>>=1,r>>=1) {
if ((l&1)==0) ans+=sum[l+1];
if ((r&1)==1) ans+=sum[r-1];
}
return ans;
}
void swap(int x)
{
if (!x) return ;
int e;
e=l[x],l[x]=r[x],r[x]=e;
sw[x]^=1;
}
void pushdown(int x)
{
if (!x) return ;
if (sw[x]) {
swap(l[x]),swap(r[x]);
sw[x]=0;
}
}
int Max(int x,int y)
{
return (w[x]<w[y]) ? x : y;
}
void updata(int x)
{
if (!x) return ;
M[x]=Max(M[l[x]],Max(M[r[x]],x));
}
void right(int x)
{
int y=rt[x],z=rt[y];
l[y]=r[x],rt[r[x]]=y;
r[x]=y,rt[y]=x;
if (l[z]==y) l[z]=x;else if (r[z]==y) r[z]=x;
rt[x]=z;
updata(y);
}
void left(int x)
{
int y=rt[x],z=rt[y];
r[y]=l[x],rt[l[x]]=y;
l[x]=y,rt[y]=x;
if (l[z]==y) l[z]=x;else if (r[z]==y) r[z]=x;
rt[x]=z;
updata(y);
}
void splay(int x)
{
pushdown(x);
for (int y,z;l[rt[x]]==x || r[rt[x]]==x;) {
y=rt[x],z=rt[y];
if (l[z]==y || r[z]==y) pushdown(z);
pushdown(y),pushdown(x);
if (l[y]==x) {
if (l[z]==y) right(y);
right(x);
}
else if (r[y]==x) {
if (r[z]==y) left(y);
left(x);
}
}
updata(x);
}
void access(int x)
{
splay(x);
l[x]=0,updata(x);
for (;rt[x];) {
int y=rt[x];
splay(y);
l[y]=x,updata(y);
splay(x);
}
}
int Ask(Line L)
{
access(L.l),access(L.r);
splay(L.l);
int root=rt[L.l];
if (!root) root=L.l;
access(root);
splay(L.r);
// cout<<root<<endl;
if (rt[L.r]!=root && root!=L.r) return 0;
splay(L.l);
int X=0;
if (root!=L.l) X=Max(M[L.l],X);
if (root!=L.r) X=Max(M[L.r],X);
return X;
}
bool cmp(Ques i,Ques j)
{
return i.r<j.r;
}
void del(int X,Line R,int Y)
{
Line id=L[w[X]];
access(X);
splay(id.l),splay(id.r);
int e,v;
if (rt[id.l]==X) e=id.l,v=id.r;else e=id.r,v=id.l;
access(v);
rt[e]=rt[X]=0;
}
void link(int X,Line R,int Y)
{
int e=R.l,v=R.r;
access(e),access(v);
swap(e);
rt[e]=Y,rt[Y]=v;
}
int main()
{
int T;
freopen("GERALD07.in","r",stdin);
freopen("output.txt","w",stdout);
scanf("%d",&T);
for (;T;T--) {
scanf("%d%d%d",&n,&m,&q);
// cout<<n<<' '<<m<<' '<<q<<endl;
for (int i=1;i<=m;i++)
scanf("%d%d",&L[i].l,&L[i].r);
for (int i=1;i<=q;Q[i].i=i,i++)
scanf("%d%d",&Q[i].l,&Q[i].r);
sort(Q+1,Q+q+1,cmp);
origin();
for (int i=1,j=1;i<=m && j<=q;i++) {
if (L[i].l!=L[i].r) {
int id=Ask(L[i]);
// cout<<i<<' '<<id-n<<endl;
// cout<<L[w[id]].l<<' '<<L[w[id]].r<<endl;
// cout<<L[i].l<<' '<<L[i].r<<endl;
if (id) {
change(w[id],0);
del(id,L[i],i+n);
}
link(id,L[i],i+n);
change(i,1);
}
for (;Q[j].r<=i && j<=q;j++) {
int sum=ask(Q[j].l,Q[j].r);
Ans[Q[j].i]=n-sum;
}
}
for (int i=1;i<=q;i++) printf("%d\n",Ans[i]);
}
return 0;
}