NKOJ P2300 何老板搬砖
再不改线段树格式我倒立女装
KONO题面哒!
暑假到了,你去给何老板打工,何老板问你会什么,你说只会搬砖。
于是,何老板想检验一下你搬砖的实力:
何老板有n块白色的方砖(编号1到n),他叫你把这n块按编号摆成了一条直线。
你以为摆成直线就完事了吗?何老板是个很古怪的人,他还不停的向你发号司令,他的命令有下列三种:
一.把第a到第b块砖换成颜色为c的砖。
二.把第a到第b块砖中颜色为c的砖换成颜色为d的砖。
三.回答第a到第b块砖中有哪几种不同的颜色。
你要快速给出每次提问的正确答案,不然你就得不到这份工作了!
(何老板的砖最多有7种不同的颜色,编号1到7,白色编号为1)。
数据范围:
$ n\leq 200000,m\leq 100000$
十次线段树爆炸十一次都是因为Pushdown的左右区间赋错值,我整个人都裂开
第一眼看到颜色只有7个就知道是状压。但是我想了半天没有想出来状压怎么写,于是搞了个暴力做法。开7棵线段树,记录每个颜色在当前区间内有多少个砖头。
每个1号操作擦除其余六棵树上的所有值,当前树把区间内砖头设为区间长度。
每个2号操作找到\(C\)树上目标区间内存在砖头的区间,把这些区间擦掉,再把\(D\)树上的这些区间设为区间长度。
每个3号操作就统计每棵树目标区间内存不存在值。
很暴力,但做了一点微小的优化后跑的飞飞飞飞快。
#include<cstdio>
#include<iostream>
#include<cmath>
#include<algorithm>
#include<cstring>
#define tp(p) if((p<<1|1)<=1200010)
using namespace std;
char *p1,*p2,buf[1<<20];
#define GC (p1==p2&&(p1=buf,p2=buf+fread(buf,1,1<<20,stdin),p1==p2)?0:(*(p1++)))
//#define GC getchar()
inline int in()
{
int x=0,w=0;
char ch=0;
while(!isdigit(ch)){
w|=ch=='-';
ch=GC;
}
while(isdigit(ch)){
x=(x<<3)+(x<<1)+(ch^48);
ch=GC;
}
return w?-x:x;
}
int n,m;
inline int ls(int x){return x<<1;}
inline int rs(int x){return x<<1|1;}
const int maxn=300010;
struct tree{
int sum[4*maxn],tag[4*maxn];
void pushup(int p){
sum[p]=sum[ls(p)]+sum[rs(p)];
}
void pushdown(int p,int l,int r){
int mid=((l+r)>>1);
if(tag[p]==1){
sum[ls(p)]=mid-l+1;
sum[rs(p)]=r-mid;
tag[ls(p)]=tag[rs(p)]=1;
}
else if(tag[p]==-1){
sum[ls(p)]=sum[rs(p)]=0;
tag[rs(p)]=tag[ls(p)]=-1;
}
tag[p]=0;
}
void ins(int l,int r,int p,int l1,int r1,int k)
{
pushdown(p,l1,r1);
if(l<=l1&&r>=r1){
if(k==1){
sum[p]=r1-l1+1;
tag[p]=1;
}
else{
sum[p]=0;
tag[p]=-1;
}
return;
}
int mid=((l1+r1)>>1);
if(mid>=l)ins(l,r,ls(p),l1,mid,k);
if(mid<r)ins(l,r,rs(p),mid+1,r1,k);
pushup(p);
return;
}
bool gs(int l,int r,int p,int l1,int r1)
{
pushdown(p,l1,r1);
if(l<=l1&&r>=r1){
return sum[p];
}
int mid=((l1+r1)>>1);
bool res=0;
if(mid>=l)res=(res|gs(l,r,ls(p),l1,mid));
if(mid<r)res=(res|gs(l,r,rs(p),mid+1,r1));
return res;
}
}tr[8];
void change(int l,int r,int p,int l1,int r1,int c,int d)
{
tr[c].pushdown(p,l1,r1);
tr[d].pushdown(p,l1,r1);
if(tr[c].sum[p]==0)return;
if(l<=l1&&r>=r1&&tr[c].sum[p]==r1-l1+1){
tr[c].sum[p]=0;
tr[c].tag[p]=-1;
tr[d].sum[p]=r1-l1+1;
tr[d].tag[p]=1;
return;
}
if(l1==r1)return;
int mid=((l1+r1)>>1);
if(mid>=l)change(l,r,ls(p),l1,mid,c,d);
if(mid<r)change(l,r,rs(p),mid+1,r1,c,d);
tr[c].pushup(p);
tr[d].pushup(p);
return;
}
int main()
{
int i,j;
n=in();m=in();
tr[1].ins(1,n,1,1,n,1);
for(i=1;i<=m;i++){
int ch,a,b,c;
ch=in();a=in();b=in();
switch(ch){
case 1:{
c=in();
for(j=1;j<=7;j++){
if(j==c)continue;
tr[j].ins(a,b,1,1,n,0);
}
tr[c].ins(a,b,1,1,n,1);
break;
}
case 2:{
int d;
c=in();d=in();
change(a,b,1,1,n,c,d);
break;
}
case 3:{
for(j=1;j<=7;j++)
{
if(tr[j].gs(a,b,1,1,n)){
printf("%d ",j);
}
}
printf("\n");
break;
}
}
}
return 0;
}
接下来是神佬zmr的状压做法
#include<stdio.h>
#include<bits/stdc++.h>
#define cut(l,r) ((l+r)>>1)
#define lson(i) (i<<1)
#define rson(i) ((i<<1)|1)
#define ll long long
#define intinf 1000000000
#define llinf 1000000000000000000LL
#define reint register int
#define st first
#define nd second
using namespace std;
char *p1,*p2,buf[1<<20];
#define GC (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<20,stdin),p1==p2)?0:*p1++)
//#define GC getchar()
inline int rd()
{
int w=0,x=0;char ch=0;
while(!isdigit(ch)){w|=ch=='-';ch=GC;}
while(isdigit(ch)){x=(x<<3)+(x<<1)+(ch^48);ch=GC;}
return w?-x:x;
}
char pbuf[1<<20],*pp=pbuf;
void push(const char c){
if(pp-pbuf==(1<<20)) fwrite(pbuf,1,(1<<20),stdout),pp=pbuf;
*pp++=c;
}
inline void wt(int x){
static int sta[35];int top=0;
do{sta[top++]=x%10,x/=10;}while(x);
while(top) push(sta[--top]+'0');
}
#define pn push('\n')
#define pk push(' ')
const int maxn=2e5+110;
const int maxr=maxn*4;
int n,m,a,b,c,d,id;
typedef pair<bool,pair<short,short> > arr;
struct node{
int l,r;
short sum;
vector<arr>to_do;
}tree[maxn*4];
inline void push_up(int i)
{
tree[i].sum=(tree[lson(i)].sum|tree[rson(i)].sum);
}
inline void push_down(int i)
{
//标记为1表示换成颜色为change的砖
//标记为2表示将change_from颜色的砖转换成颜色为change_to的砖
if(!tree[i].to_do.size())return;
arr tmp,t;
int ls=lson(i),rs=rson(i);
short fr,to;
vector<arr>::iterator it;
for(it=tree[i].to_do.begin();it!=tree[i].to_do.end();it++)
{
tmp=*it;fr=tmp.nd.st;to=tmp.nd.nd;
if(tmp.st==false)
{
while(tree[ls].to_do.size()) tree[ls].to_do.erase(tree[ls].to_do.begin());
while(tree[rs].to_do.size()) tree[rs].to_do.erase(tree[rs].to_do.begin());
tree[ls].sum=(1<<(fr-1));
tree[rs].sum=(1<<(fr-1));
t.st=false;t.nd.st=fr;
tree[ls].to_do.push_back(t);
tree[rs].to_do.push_back(t);
}
else
{
t.st=true;t.nd.st=fr;t.nd.nd=to;
if(tree[ls].sum&(1<<(fr-1)))
{
tree[ls].sum=(tree[ls].sum^(1<<fr-1));
tree[ls].sum=(tree[ls].sum|(1<<(to-1)));
tree[ls].to_do.push_back(t);
}
if(tree[rs].sum&(1<<(fr-1)))
{
tree[rs].sum=(tree[rs].sum^(1<<fr-1));
tree[rs].sum=(tree[rs].sum|(1<<(to-1)));
tree[rs].to_do.push_back(t);
}
}
}
while(tree[i].to_do.size()) tree[i].to_do.erase(tree[i].to_do.begin());
}
inline void build(int i,int l,int r)
{
tree[i].l=l;tree[i].r=r;tree[i].sum=1;
if(l==r) return;
int mid=cut(tree[i].l,tree[i].r);
build(lson(i),l,mid);
build(rson(i),mid+1,r);
push_up(i);
}
inline void change1(int i,int l,int r,int col)
{
if(tree[i].l>=l&&tree[i].r<=r)
{
while(tree[i].to_do.size()) tree[i].to_do.erase(tree[i].to_do.begin());
arr tmp;tmp.st=false;tmp.nd.st=col;
tree[i].to_do.push_back(tmp);
tree[i].sum=(1<<(col-1));
return;
}
push_down(i);
int mid=cut(tree[i].l,tree[i].r);
if(mid>=l) change1(lson(i),l,r,col);
if(mid<r) change1(rson(i),l,r,col);
push_up(i);
}
inline void change2(int i,int l,int r,int fr,int to)
{
if(tree[i].l>=l&&tree[i].r<=r)
{
arr tmp;tmp.st=true;tmp.nd.st=fr;tmp.nd.nd=to;
if(tree[i].sum&(1<<(fr-1)))
{
tree[i].sum-=(1<<(fr-1));
tree[i].sum=(tree[i].sum|(1<<(to-1)));
tree[i].to_do.push_back(tmp);
}
return;
}
push_down(i);
int mid=cut(tree[i].l,tree[i].r);
if(mid>=l) change2(lson(i),l,r,fr,to);
if(mid<r) change2(rson(i),l,r,fr,to);
push_up(i);
}
inline int getans(int i,int l,int r)
{
if(tree[i].l>=l&&tree[i].r<=r)
return tree[i].sum;
push_down(i);
int mid=cut(tree[i].l,tree[i].r);short res=0;
if(mid>=l) res=(res|getans(lson(i),l,r));
if(mid<r) res=(res|getans(rson(i),l,r));
return res;
}
int main()
{
n=rd();m=rd();
build(1,1,n);
for(reint i=1;i<=m;i++)
{
id=rd();
if(id==1)
{
a=rd();b=rd();c=rd();
change1(1,a,b,c);
}
else if(id==2)
{
a=rd();b=rd();c=rd();d=rd();
change2(1,a,b,c,d);
}
else
{
a=rd();b=rd();
int ans=getans(1,a,b);
for(short j=1;j<=7;j++)
if(ans&(1<<(j-1))) push(j+'0'),pk;
pn;
}
}
fwrite(pbuf,1,pp-pbuf,stdout);
return 0;
}
C96改造wsl!