JZOJ 5387【GDOI2018模拟9.23】动态图
来源:互联网 发布:二次元图片软件 编辑:程序博客网 时间:2024/05/15 06:03
题目
Time Limits: 1000 ms Memory Limits: 262144 KB
Description
Input
Output
Sample Input
5 3 0
1 4 5
1 2 4
3 1 2
Sample Output
3
Data Constraint
题解
鸟(雀)题一道。。。
做法:函数式线段树+lct
在每一次加入一条边i的时候,我们记录一个last[i]
如果在当前情况下加入了这一条边之后构成了一个环,last[i]就表示这个环里面最小的边的编号(也就是最早加进来的边),然后我们把这条边删除并且把这条边加进来
如果没有构成环我们就直接把这一条边加进来并且last[i]=0
然后对于询问(l,r),答案就是n减去x∈[l,r] last[x]∈[0,l)的数量
原因就是:
如果last[x]∈[l,x),就表示如果我们依次加入l–r的边,那么在加到边x的时候边x对应的两个点已经属于一个联通块了,连上这一条边并不会减少一个联通块,反之则会减少一个联通块
对于删边,我们发现只会删去最后一条边,所以我们可以用一个函数式线段树来实现这样的删除
对于重边我们需要进行特殊的处理,这个也比较简单
一开始我判断两个点是否在同一个联通块的判断函数打错了,我天真的以为和cut是一样的
后来仔细想了想cut是因为两个点之间有边,换根之后两个点的深度肯定一个是1一个是2所以这样打才是对的,但是判断函数不是
于是就想到了把x,y都换根一次,看看y换完之后x还是不是根,这样就可以判断了
贴代码
#include<iostream>#include<algorithm>#include<cstdio>#include<cstring>#include<cmath>#define fo(i,a,b) for(i=a;i<=b;i++)#define fo1(i,b,a) for(i=b;i>=a;i--)#define min(x,y) ((x)<(y)?(x):(y))using namespace std;const int maxn=2e6+5;int tree[maxn*2][4],fa[maxn],son[maxn][3],mi[maxn];int la[maxn],a[maxn][3],root[maxn],d[maxn];bool bz[maxn];int i,j,k,m,n,x,y,q,ty,ans,p,now,z,u,v,o,zsc,l,r;char ch;int read(){ int x=0; ch=getchar(); while (ch<'0' || ch>'9') ch=getchar(); while (ch>='0' && ch<='9'){ x=x*10+ch-48; ch=getchar(); } return x;}bool isroot(int x){ if (son[fa[x]][1]!=x && son[fa[x]][2]!=x) return true; else return false;}void remark(int x){ if (bz[x]){ bz[x]=false; bz[son[x][1]]^=1; bz[son[x][2]]^=1; int t=son[x][1]; son[x][1]=son[x][2]; son[x][2]=t; }}void update(int x){ mi[x]=mi[son[x][1]]; if (mi[son[x][2]] &&(mi[x]==0 || mi[x]>mi[son[x][2]])) mi[x]=mi[son[x][2]]; if (x>n && (mi[x]==0 || mi[x]>x-n)) mi[x]=x-n;}void rotate(int x,int w){ int y=fa[x]; son[y][3-w]=son[x][w]; if (son[x][w]) fa[son[x][w]]=y; if (!isroot(y)){ if (son[fa[y]][1]==y) son[fa[y]][1]=x; else son[fa[y]][2]=x; } fa[x]=fa[y]; fa[y]=x; son[x][w]=y; update(y); update(x);} void splay(int x){ int i,y; d[0]=0; while (!isroot(x)){ d[++d[0]]=x; x=fa[x]; } d[++d[0]]=x; fo1(i,d[0],1) remark(d[i]); x=d[1]; while (!isroot(x)){ y=fa[x]; if (isroot(y)){ if (x==son[y][1]) rotate(x,2); else rotate(x,1); } else{ if (y==son[fa[y]][1]){ if (x==son[y][1]){ rotate(y,2); rotate(x,2); } else{ rotate(x,1); rotate(x,2); } } else{ if (x==son[y][2]){ rotate(y,1); rotate(x,1); } else{ rotate(x,2); rotate(x,1); } } } }}void access(int x){ for(int t=0;x;x=fa[x]) splay(x),son[x][2]=t,update(x),t=x;}void makeroot(int x){ access(x); splay(x); bz[x]^=1;}void link(int x,int y){ makeroot(x); fa[x]=y;}void cut(int x,int y){ makeroot(x); access(y); splay(y); son[y][1]=0; fa[x]=0; update(y);}int find(int x,int y){ makeroot(x); access(y); splay(y); return mi[y];}bool tong(int x,int y){ makeroot(x); makeroot(y); if (isroot(x)) return false; else return true;}void maketree(int v,int l,int r,int x){ tree[++p][1]=tree[v][1]; tree[p][2]=tree[v][2]; tree[p][3]=tree[v][3]+1; if (l==r) return; int mid=(l+r)/2; if (x<=mid){ tree[p][1]=p+1; maketree(tree[v][1],l,mid,x); } else{ tree[p][2]=p+1; maketree(tree[v][2],mid+1,r,x); }}void find(int zo,int yo,int l,int r,int x,int y){ if (l==x && r==y){ z=z+tree[yo][3]-tree[zo][3]; } else{ int mid=(l+r)/2; if (y<=mid) find(tree[zo][1],tree[yo][1],l,mid,x,y); else if (x>mid) find(tree[zo][2],tree[yo][2],mid+1,r,x,y); else{ find(tree[zo][1],tree[yo][1],l,mid,x,mid); find(tree[zo][2],tree[yo][2],mid+1,r,mid+1,y); } }}int main(){ freopen("graph.in","r",stdin); freopen("graph.out","w",stdout); n=read(); q=read(); ty=read(); fo(zsc,1,q){ z=read(); if (z==1){ u=read(); v=read(); if (ty){ u=1+(u xor ans)%n; v=1+(v xor ans)%n; } ++now; a[now][1]=u; a[now][2]=v; if (u==v){ root[now]=root[now-1]; continue; } if (! tong(u,v)){ mi[now+n]=now; link(u,now+n); link(v,now+n); } else{ o=find(u,v); la[now]=o; cut(o+n,a[o][1]); cut(o+n,a[o][2]); mi[now+n]=now; link(u,now+n); link(v,now+n); } root[now]=p+1; maketree(root[now-1],0,q,la[now]); a[now][1]=u; a[now][2]=v; } else if (z==2){ if (a[now][1]==a[now][2]){ now--; continue; } cut(n+now,a[now][1]); cut(n+now,a[now][2]); if (la[now]){ mi[la[now]+n]=la[now]; link(a[la[now]][1],la[now]+n); link(a[la[now]][2],la[now]+n); } la[now]=0; now--; } else{ x=read(); y=read(); if (ty){ u=1+(x xor ans)%now; v=1+(y xor ans)%now; x=min(u,v); y=max(u,v); } z=0; find(root[x-1],root[y],0,q,0,x-1); ans=n-z; printf("%d\n",ans); } } return 0;}
阅读全文
0 0
- JZOJ 5387【GDOI2018模拟9.23】动态图
- 【GDOI2018模拟9.23】动态图
- 【GDOI2018模拟9.23】动态图
- 【JZOJ 5239】 【GDOI2018模拟8.7】图的异或
- 【JZOJ 5205】【GDOI2018模拟7.6】仰望星空
- 【JZOJ 5220】【GDOI2018模拟7.10】C
- JZOJ 5221. 【GDOI2018模拟7.10】A
- 【JZOJ 5204】【GDOI2018模拟7.6】吃干饭
- 【JZOJ 5250】【GDOI2018模拟8.11】质数
- 【GDOI2018模拟9.23】博弈
- JZOJ 5207【GDOI2018模拟7.7】暴力大神hxx
- 【JZOJ 5215】【GDOI2018模拟7.9】组合数问题
- JZOJ 5224【GDOI2018模拟7.12】C(数论&&杜教筛)
- 【JZOJ 5229】【GDOI2018模拟7.14】小奇的糖果
- 【JZOJ 5241】【GDOI2018模拟8.8】苹果和雪梨
- 【jzoj5219】【GDOI2018模拟7.10】【B】【动态规划】
- 【GDOI2018模拟7.10】B 动态规划
- 【GDOI2018模拟7.10】C 动态规划
- static与C#中的static
- 网络编程预习一
- android studio 3中如何使用recyclerview布局
- python/caffe/_caffe.cpp:10:31: fatal error: numpy/arrayobject.h: No such file or directory
- 浅谈Linux服务器问题解决
- JZOJ 5387【GDOI2018模拟9.23】动态图
- 编写多线程程序,模拟多个人通过一个山洞。这个山洞每次只能通过一个人,每个人通过山洞的时间为2秒(sleep)。随机生成10个人,都要通过此山洞,用随机值对应的字符串表示人名,打印输出每次通过山洞的人名
- cmder windows下命令行神器
- Spiral Matrix
- Windows安装和配置JDK(详细图解)
- Nginx的优缺点
- CSS(三)
- 淘宝秒杀系统内幕
- Cause: java.sql.SQLException: 无效的列类型: 1111(Mybatis中insert插入空值时,需要指定JdbcType)