Luogu P2391 白雪皑皑 && BZOJ 2054: 疯狂的馒头 并查集

4月的时候在luogu上做过 白雪皑皑 这道题,当时一遍AC可高兴了qwq,后来去了个厕所,路上忽然发现自己的做法是错的qwq。。。然后就咕咕了qwq

今天看到了 疯狂的馒头 ,发现一毛一样OvO。。。还是好好做一下吧QWQ

先上个错误代码(虽然BZOJ和Luogu都A了)

// luogu-judger-enable-o2
#include<cstdio>
#include<iostream>
#define R register int
#define getchar() *S++
using namespace std;
char RR[50000005],*S=RR;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,m,p,q;
int vl[1000010],pre[1000010],nxt[1000010];
signed main() {
    fread(RR,sizeof(RR),1,stdin);
    n=g(),m=g(),p=g(),q=g();
    for(R i=1;i<=n;++i) pre[i]=i-1,nxt[i]=i+1;
    for(R i=m;i>=1;--i) {R l=(i*p+q)%n+1,r=(i*q+p)%n+1; if(l>r) swap(l,r);
        if(!vl[l]) for(R j=l;j<=r;j=nxt[j]) vl[j]=i,nxt[pre[j]]=nxt[j],pre[nxt[j]]=pre[j];
        if(!vl[r]) for(R j=r;j>=l;j=pre[j]) vl[j]=i,nxt[pre[j]]=nxt[j],pre[nxt[j]]=pre[j];
    } for(R i=1;i<=n;++i) printf("%d\n",vl[i]); 
}

首先倒序处理显然吧。。。已经染过色的就不用再染了。。

但是这样判断显然是不对的:只判了左右端点不能确定中间有没有染色。。。问题是不能动态更新fa

刚刚本来想hack一下自己,结果发现不会造数据。。。。莫非这数据是有规律的导致我AC了???不知。。。懒得对拍了。。。如果大佬有想法可以评论,救救这只不知所对(不知所错)的蒟蒻、、qwq

好,扯完皮说正解:

用并查集当做链表(???)。。。还是倒序处理,如果这个区间已经染了,那么向右合并。注意每次读取fa时是要用getf来路径压缩,而不能直接取fa,否则不能更新

#include<cstdio>
#include<iostream>
#define R register int
using namespace std;
const int N=1E+6,M=1E+7;
inline int g() {
    R ret=0,fix=1; register char ch; while(!isdigit(ch=getchar())) fix=ch=='-'?-1:fix;
    do ret=ret*10+(ch^48); while(isdigit(ch=getchar())); return ret*fix;
}
int n,m,p,q,cnt;
int fa[N],a[N];
inline int getf(int x) {return x==fa[x]?x:fa[x]=getf(fa[x]);}
signed main() { 
    n=g(),m=g(),p=g(),q=g(); 
    for(R i=1;i<=n+1;++i) fa[i]=i;
    for(R i=m;i;--i) { R l=(i*p+q)%n+1,r=(i*q+p)%n+1;
        if(l>r) swap(l,r);
        for(R j=getf(l);j<=r;j=getf(j)) {a[j]=i,fa[j]=j+1,++cnt; if(cnt==n) break;}
        if(cnt==n) break;
    } for(R i=1;i<=n;++i) printf("%d\n",a[i]);
}

AC!=correct 2019.05.06

猜你喜欢

转载自www.cnblogs.com/Jackpei/p/10819384.html