Description
Input
Output
Sample Input
5 3 0
1 4 5
1 2 4
3 1 2
Sample Output
3
Solution
动态图?用动态树来做
先只考虑离线
所有询问按照右端点排序
按照边从前往后加入
相当于维护一个生成树
如果一条边加入会形成环,那么就替换掉这个环上最早出现的边
为什么是正确的呢?
询问的右端点固定,左端点不同,我的边尽量靠近右端点,就可以保证答案最优
答案就是n-这些边加入了LCT的数量
那么维护的就是最大生成树
每次加边替换掉某条边的时候记录下来
再删边的时候就可以还原回去
用一个树状数组或者线段树记录每条边是否出现就可以维护答案了
如果你理解了的话,就会发现在线也是一样的
把维护答案的数据结构改成可以可持久化的(可持久化线段树)就行了
这题想到不难,难的是你需要种两棵树
另附出数据程序,在标程的下面
Code
#include<cstdio>
#include<cstring>
#include<algorithm>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 1010000
#define M 2010000
using namespace std;
int n,m,to,cty,a[N],t1=0,t2=0,b[M],c[M],rev[M],p[M],fa[M],t[M][2],s[M],size[M],d[M],ans,bz[N],r[N];
struct node{
int x,y,z;
}bi[N];
struct note{
int l,r,d;
}ta[M*5];
void ins(int v,int i,int j,int x,int y)
{
ta[v].d+=y;
if(i==j) return;
int mid=(i+j)/2;
if(x<=mid) ta[++to]=ta[ta[v].l],ta[v].l=to,ins(ta[v].l,i,mid,x,y);
else ta[++to]=ta[ta[v].r],ta[v].r=to,ins(ta[v].r,mid+1,j,x,y);
}
int gans(int v,int i,int j,int x,int y)
{
if(v==0) return 0;
if(i==x&&j==y) return ta[v].d;
int mid=(i+j)/2;
if(y<=mid) return gans(ta[v].l,i,mid,x,y);
else if(x>mid) return gans(ta[v].r,mid+1,j,x,y);
else return gans(ta[v].l,i,mid,x,mid)+gans(ta[v].r,mid+1,j,mid+1,y);
}
void update(int x)
{
size[x]=size[t[x][0]]+size[t[x][1]]+b[x];
if(c[x]) d[x]=c[x];else d[x]=2147483647;
if(t[x][0]) d[x]=min(d[x],d[t[x][0]]);
if(t[x][1]) d[x]=min(d[x],d[t[x][1]]);
}
void down(int x)
{
if(!rev[x]) return;
swap(t[x][0],t[x][1]);
rev[t[x][0]]^=1;rev[t[x][1]]^=1;
rev[x]=0;
}
void xc(int x)
{
for(;x;x=fa[x]) s[++s[0]]=x;
for(;s[0];s[0]--) down(s[s[0]]);
}
int lr(int x){return x==t[fa[x]][1];}
void rotate(int x)
{
int y=fa[x],k=lr(x);
t[y][k]=t[x][1-k];if(t[x][1-k]) fa[t[x][1-k]]=y;
fa[x]=fa[y];
if(fa[y]) t[fa[y]][lr(y)]=x;
else p[x]=p[y],p[y]=0;
t[x][1-k]=y;fa[y]=x;
update(y);update(x);
}
void splay(int x,int y)
{
xc(x);
while(fa[x]!=y)
{
if(fa[fa[x]]!=y)
if(lr(x)==lr(fa[x])) rotate(fa[x]);
else rotate(x);
rotate(x);
}
}
void access(int x)
{
int y=0;
while(x)
{
splay(x,0);
fa[t[x][1]]=0;p[t[x][1]]=x;
t[x][1]=y;fa[y]=x;p[y]=0;
update(x);
y=x;x=p[x];
}
}
void makeroot(int x)
{
access(x);splay(x,0);rev[x]^=1;
}
void link(int x,int y)
{
makeroot(x);p[x]=y;
}
void cut(int x,int y)
{
makeroot(x);access(y);splay(y,0);
t[y][0]=fa[x]=p[x]=0;update(y);
}
int main()
{
freopen("graph.in","r",stdin);
freopen("graph.out","w",stdout);
scanf("%d%d%d",&n,&m,&cty);to=m;
int tot=0,bkill=0;
memset(a,0,sizeof(a));
int j=0,hzj=0;
fo(i,1,m)
{
int ac;scanf("%d",&ac);
if(ac==2)
{
hzj++;ta[hzj]=ta[hzj-1];
int eb=tot;while(bz[eb]) eb--;bz[eb]=1;
int z=eb;bkill++;bi[j].z=bkill;j--;
if(bi[z].x==bi[z].y) continue;
cut(bi[z].x,z+n);cut(z+n,bi[z].y);ins(hzj,1,m,z,-1);
z=a[z];
if(z==0) continue;
if(bi[z].x==bi[z].y) continue;
c[z+n]=z;link(bi[z].x,z+n);link(z+n,bi[z].y);ins(hzj,1,m,z,1);
}
if(ac==1)
{
hzj++;ta[hzj]=ta[hzj-1];
int x,y,z=++tot;r[z]=hzj;
scanf("%d%d",&x,&y);
if(cty) x=(x^ans)%n+1,y=(y^ans)%n+1;
bi[z].x=x;bi[z].y=y;bi[++j].z=bkill;
if(x==y) continue;
b[y]=1;makeroot(x);access(y);
splay(x,0);
if(size[x]==0)
{
c[z+n]=z;link(x,z+n);link(z+n,y);ins(hzj,1,m,z,1);
}
else
{
splay(x,0);int k=d[x];
cut(bi[k].x,k+n);cut(k+n,bi[k].y);ins(hzj,1,m,k,-1);
a[z]=k;c[z+n]=z;ins(hzj,1,m,z,1);
link(x,z+n);link(z+n,y);
}
b[y]=0;
}
if(ac==3)
{
int x,y;scanf("%d%d",&x,&y);
if(cty) x=(x^ans)%j+1,y=(y^ans)%j+1;
if(x>y) swap(x,y);
x+=bi[x].z;y+=bi[y].z;
ans=gans(r[y],1,m,x,y);
ans=n-ans;
printf("%d\n",ans);
}
}
}
出数据
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<ctime>
#define fo(i,a,b) for(int i=a;i<=b;i++)
#define N 1010000
using namespace std;
int tot;
int main()
{
freopen("graph.in","w",stdout);
int n=10,m=20;//修改这里获得不同的数据规模
printf("%d %d 0\n",n,m);
srand((unsigned)time(0));
fo(i,1,m)
{
int z=rand()%3+1;
while(tot<=2&&(z==2||z==3)) z=rand()%3+1;
if(z==1)
{
int x=rand()%n+1,y=rand()%n+1;
printf("%d %d %d\n",z,x,y);
tot++;
}
if(z==2) printf("%d\n",z),tot--;
if(z==3)
{
int x=rand()%(tot-1)+1,y=rand()%(tot-x)+1+x;
printf("%d %d %d\n",z,x,y);
}
}
}