【BZOJ2054疯狂的馒头】各种瞎搞
就是瞎搞
BZOJ2054(权限题)
很容易想到倒着搞,面对已经涂过就不搞,涂完了就结束了。想到区间覆盖,segment tree就砸上来了
但不知为什么比线段树还慢一定我太弱了)
python:
2054: 疯狂的馒头
Time Limit: 10 Sec Memory Limit: 162 MB Submit: 1408 Solved: 598 [Submit][Status][Discuss]Description

Input
第一行四个正整数N,M,p,q
Output
一共输出N行,第i行表示第i个馒头的最终颜色(如果最终颜色是白色就输出0)。
Sample Input
4 3 2 4
Sample Output
2
2
3
0
HINT

#include<iostream> #include<cstdio> #include<cstring> #include<cmath> #include<algorithm> using namespace std; const int maxn = 1000005; const int maxm = 10000005; const int inf = 1e9+7; int n,m,p,q; int tl[maxm],tr[maxm]; struct node { node *ls,*rs; int laz; }z[maxn*2],*rt;int tot; int all; void add(node *&p,int l,int r,int x,int y,int col) { if(p->laz>0) return; if(p->laz==0&&x<=l&&r<=y) { p->laz = col; all+=r-l+1; return; } int mid = (l+r)>>1; if(y<=mid) add(p->ls,l,mid,x,y,col); else if(x>mid) add(p->rs,mid+1,r,x,y,col); else add(p->ls,l,mid,x,y,col),add(p->rs,mid+1,r,x,y,col); if(p->ls->laz>0&&p->rs->laz>0) { if(p->ls->laz==p->rs->laz) p->laz = p->ls->laz; else p->laz = inf; } else p->laz = -1; } void bl(node *&p,int l,int r) { if(p->laz>0&&p->laz!=inf) { for(int i=l;i<=r;i++) printf("%d\n",p->laz);return; } if(l==r) { printf("0\n"); return; } int mid = (l+r)>>1; bl(p->ls,l,mid); bl(p->rs,mid+1,r); } void make(node *&p,int l,int r){ p = &z[++tot]; if(l==r) return; int mid = (l+r)>>1; make(p->ls,l,mid); make(p->rs,mid+1,r); } int main() { scanf("%d%d%d%d",&n,&m,&p,&q); for(int i=1;i<=m;i++) { tl[i] = (1ll*i*p+q)%n+1; tr[i] = (1ll*i*q+p)%n+1; if(tl[i]>tr[i]) swap(tl[i],tr[i]); } make(rt,1,n); for(int i=m;i;i--) { add(rt,1,n,tl[i],tr[i],i); if(all==n) break; } bl(rt,1,n); }咳咳,可我们注意到对于线段树一个结点如果涂满了再也不会变了。那么其实对于在一个单点上也是同理,只要这个单点用过了,就再也不会用了。如果我们从左向右涂色,那么意味着到某个涂过色的结点,就可以跳过那一大段,直接跳向下一个没有涂过色的结点(其实原来一次luogu月赛也见过这样的技巧,只是当时太弱,,现在更弱)。那么我们利用并查集来维护一个类似链表的东西,每次直接跳向下一个没涂的结点,然后每次暴力瞎搞就可以了(反阿克曼大法好!)。代码短多啦!(
fa = [int(0)]*1000005 col = [int(0)]*1000005 def gf(x): #print(x,fa[x]) if(int(fa[x])==int(x)): return x else: fa[x]=gf(fa[x]) return fa[x] def main(): n,m,p,q=map(int,input().split()) for i in range(1,n+2,1): fa[i]=i; for i in range(m,0,-1): l = (i*p+q)%n+1 r = (i*q+p)%n+1 if(l>r):swap(l,r) j = gf(l) al = 0 while(j<=r): col[j]=i; al+=1 fa[j]=j+1 j=gf(j) if(al==n):break; for i in range(i,n+1): print(col[i]) main()C++:
#include<iostream> #include<algorithm> #include<cstdio> using namespace std; const int maxn = 1000005; int n,m,p,q; int fa[maxn],col[maxn],all; int gf(int x) { return fa[x]==x?fa[x]:fa[x]=gf(fa[x]); } int main() { scanf("%d%d%d%d",&n,&m,&p,&q); for(int i=1;i<=n+1;i++) fa[i] = i; for(int i=m;i;i--) { int l = (1ll*i*p+q)%n+1; int r = (1ll*i*q+p)%n+1; if(l>r) swap(l,r); for(int j=gf(l);j<=r;j=gf(j)) { col[j] = i; ++all; fa[j] = j+1; } if(all==n) break; } for(int i=1;i<=n;i++) printf("%d\n",col[i]); }