【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]);
}

浙公网安备 33010602011771号