Hdu 6858 Discovery of Cycles —— LCT模板+尺取

This way

题意:

现在有一张n个点m条边的连通图,有q个询问,每次问你区间l~r的边是否能组成一个及以上的简单环。

题解:

一开始用并查集做,浪费了我2发罚时,因为加边删边的顺序需要是后进先出,否则会出问题。
那么并查集不行的话,我首选LCT,因为TOPO不能每次都快速判连通,但是LCT可以。
于是这就是一道模板题了
我枚举右端点,然后左端点向右移,知道没有环了为止,也就是一个尺取的想法。

#include<bits/stdc++.h>
#define G if(++ip==ie)if(fread(ip=buf,1,SZ,stdin))
#pragma GCC optimize(2)
#define ri register int
#define iv inline void
using namespace std;
const int N=3e5+5;
int f[N],ch[N][2],rev[N],siz[N];
const int SZ=1<<19;
char buf[SZ],*ie=buf+SZ,*ip=ie-1;
inline int in(){
    G;while(*ip<'-')G;
    ri x=*ip&15;G;
    while(*ip>'-'){x*=10;x+=*ip&15;G;}
    return x;
}
inline bool is_rt(ri x)
{
    return ch[f[x]][0]==x||ch[f[x]][1]==x;
}
int ans[N],a[N];
iv push_up(ri x)
{
    siz[x]=siz[ch[x][0]]+siz[ch[x][1]]+1;
}
iv reverse(ri x)
{
    swap(ch[x][0],ch[x][1]);
    rev[x]^=1;
}
iv push_down(ri x)
{
    if(!rev[x])
        return ;
    if(ch[x][0])
        reverse(ch[x][0]);
    if(ch[x][1])
        reverse(ch[x][1]);
    rev[x]=0;
}
iv rotate(ri x){//一次旋转
    int y=f[x],z=f[y],k=ch[y][1]==x,w=ch[x][!k];
    if(is_rt(y))ch[z][ch[z][1]==y]=x;ch[x][!k]=y;ch[y][k]=w;//额外注意if(nroot(y))语句,此处不判断会引起致命错误(与普通Splay的区别2)
    if(w)f[w]=y;f[y]=x;f[x]=z;
    push_up(y);
}
int st[N];
iv splay(ri x){//只传了一个参数,因为所有操作的目标都是该Splay的根(与普通Splay的区别3)
    ri y=x,z=0;
    st[++z]=y;//st为栈,暂存当前点到根的整条路径,pushdown时一定要从上往下放标记(与普通Splay的区别4)
    while(is_rt(y))st[++z]=y=f[y];
    while(z)push_down(st[z--]);
    while(is_rt(x)){
        y=f[x];z=f[y];
        if(is_rt(y))
            rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y);
        rotate(x);
    }
    push_up(x);
}
/*当然了,其实利用函数堆栈也很方便,代替上面的手工栈,就像这样
I pushall(R x){
    if(is_rt(x))pushall(f[x]);
    pushdown(x);
}*/
iv access(ri x){//访问
    for(ri y=0;x;x=f[y=x])
        splay(x),ch[x][1]=y,push_up(x);
}
iv makeroot(ri x){//换根
    access(x);splay(x);
    reverse(x);
}
inline int findroot(ri x){//找根(在真实的树中的)
    access(x);splay(x);
    while(ch[x][0])push_down(x),x=ch[x][0];
    splay(x);
    return x;
}
iv split(ri x,ri y){//提取路径
    makeroot(x);
    access(y);splay(y);
}
iv link(ri x,ri y){//连边
    makeroot(x);
    if(findroot(y)!=x)f[x]=y;
}
iv cut(ri x,ri y){//断边
    makeroot(x);
    if(findroot(y)==x&&f[y]==x&&!ch[y][0]){
        f[y]=ch[x][1]=0;
        push_up(x);
    }
}
struct Edge{
    int x,y;
}e[N];
int main()
{
    ri t;
    scanf("%d",&t);
    while(t--){
        memset(f,0,sizeof(f));
        memset(ch,0,sizeof(ch));
        memset(rev,0,sizeof(rev));
        memset(siz,0,sizeof(siz));
        ri n,m,q;
        n=in(),m=in(),q=in();
        for(int i=1;i<=m;i++)
            e[i].x=in(),e[i].y=in(),ans[i]=1e9;
        int l=1,r;
        for(r=1;r<=m;r++){
            int x=e[r].x,y=e[r].y;
            access(y);
            while(findroot(x)==findroot(y)){
                ans[l]=r;
                int sx=e[l].x,sy=e[l].y;
                l++;
                cut(sx,sy);
                access(y);
            }
            link(x,y);
        }
        while(l<=m)cut(e[l].x,e[l].y),l++;
        int la=0;
        while(q--){
            l=in(),r=in();
            l=(l^la)%m+1;
            r=(r^la)%m+1;
            if(l>r)swap(l,r);
            //printf("l: %d\n",l);
            if(ans[l]<=r){
                printf("Yes\n");
                la=1;
            }
            else{
                printf("No\n");
                la=0;
            }
        }
    }
    return 0;
}

经过我们队的一顿疯狂优化,时间复杂度从1400到了900
在这里插入图片描述
在这里插入图片描述

#include<bits/stdc++.h>
#pragma GCC optimize(2)
#define ll long long
using namespace std;
const int N=3e5+5;
int f[N],ch[N][2],rev[N];
namespace FAST_IO {
    #define IN_LEN 250000
    #define OUT_LEN 250000
    inline char Getchar() {
        static char buf[IN_LEN], *l=buf,*r=buf;
        if (l==r) r=(l=buf)+fread(buf,1,IN_LEN,stdin);
        return (l==r)?EOF:*l++;
    }
    char obuf[OUT_LEN], *ooh = obuf;
    inline void Putchar(char c) {
        if (ooh == obuf + OUT_LEN) fwrite(obuf, 1, OUT_LEN, stdout),ooh = obuf;
        *ooh++ = c;
    }
    inline ll rd(){
        ll x=0;int ch=Getchar(); bool f=1;
        while (!isdigit(ch)&&(ch!='-')&&(ch!=EOF)) ch=Getchar();
        if (ch=='-'){f=0;ch=Getchar();}
        while (isdigit(ch)){x=(x<<1)+(x<<3)+ch-'0';ch=Getchar();}
        return f?x:-x;
    }
    void write(ll x){ if (x>=10) write(x/10),Putchar((char)(x%10+'0')); else Putchar((char)(x+'0')); }
    inline void flush() { fwrite(obuf, 1, ooh - obuf, stdout); }
}
using namespace FAST_IO;
#define ri register int
#define iv inline void
#define ii inline int
inline bool is_rt(ri x)
{
    return ch[f[x]][0]==x||ch[f[x]][1]==x;
}
int ans[N],a[N];
iv reverse(ri x)
{
    swap(ch[x][0],ch[x][1]);
    rev[x]^=1;
}
iv push_down(ri x)
{
    if(!rev[x])
        return ;
    if(ch[x][0])
        reverse(ch[x][0]);
    if(ch[x][1])
        reverse(ch[x][1]);
    rev[x]=0;
}
iv rotate(ri x){
    int y=f[x],z=f[y],k=ch[y][1]==x,w=ch[x][!k];
    if(is_rt(y))ch[z][ch[z][1]==y]=x;ch[x][!k]=y;ch[y][k]=w;
    if(w)f[w]=y;f[y]=x;f[x]=z;
}
int st[N];
iv splay(ri x){
    ri y=x,z=0;
    st[++z]=y;
    while(is_rt(y))st[++z]=y=f[y];
    while(z)push_down(st[z--]);
    while(is_rt(x)){
        y=f[x];z=f[y];
        if(is_rt(y))
            rotate((ch[y][0]==x)^(ch[z][0]==y)?x:y);
        rotate(x);
    }
}
iv access(ri x){
    for(ri y=0;x;x=f[y=x])
        splay(x),ch[x][1]=y;
}
iv makeroot(ri x){
    access(x);splay(x);
    reverse(x);
}
ii findroot(ri x){
    access(x);splay(x);
    while(ch[x][0])push_down(x),x=ch[x][0];
    splay(x);
    return x;
}
iv split(ri x,ri y){
    makeroot(x);
    access(y);splay(y);
}
iv link(ri x,ri y){
    makeroot(x);
    f[x]=y;
}
ii finds(ri x)
{
    access(x),splay(x);
    while(ch[x][0])
        x=ch[x][0];
    return x;
}
iv cut(ri x,ri y){
    split(x,y);
    f[x]=ch[y][0]=0;
}
int xx[N],yy[N];
int main()
{
    ri t;
    t=rd();
    while(t--){
        ri n,m,q;
        n=rd(),m=rd(),q=rd();
        for(ri i=1;i<=m;++i)
            xx[i]=rd(),yy[i]=rd(),ans[i]=1e9;
        ri l=1,r;
        for(r=1;r<=m;++r){
            ri x=xx[r],y=yy[r];
            while(finds(x)==finds(y)){
                ans[l]=r;
                ri sx=xx[l],sy=yy[l];
                ++l;
                cut(sx,sy);
            }
            link(x,y);
        }
        while(l<=m)cut(xx[l],yy[l]),++l;
        int la=0;
        while(q--){
            l=rd(),r=rd();
            l=(l^la)%m+1;
            r=(r^la)%m+1;
            if(l>r)swap(l,r);
            if(ans[l]<=r){
                Putchar('Y');
                Putchar('e');
                Putchar('s');
                Putchar('\n');
                la=1;
            }
            else{
                Putchar('N');
                Putchar('o');
                Putchar('\n');
                la=0;
            }
        }
    }
    flush();
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值