P11024 做题报告
前言
调代码要笑着调
联考题目放在 T3 其实不然
NOIp 放个T2差不多了
具有多个常见的经典 trick,还是有点落实价值的
题意
给出长度为 \(n\) 的数组的终止状态,总共 \(m\) 次操作,每一次将区间 \([l,r]\) 的所有数字覆盖改为 \(c\),找到一个决策顺序,要求按照这个顺序做能正好完成所有操作并且终止状态正确,或报告无解
思路
首先肯定看见覆盖问题就会尝试将其转化,一个很板子的转化就是将操作序列倒转变成每一次修改后不会再动了,类似于 白雪皑皑 的做法,然后发现有一个很显然的贪心,那就是每一次找到一个区间内要不就是被染过色了,要不就是和现在需要染色的颜色相同的区间,将其染色,因为显然这个位置如果已经合法了,就一定不会在某一个后续时刻不合法,而我们每一次染完一个区间之后都有可能会出现新的可以染的区间,并且所有区间的染色顺序不分先后,这样我们就出了一个 \(O(nm\log_2 n) ~ O(n^2m)\) 的做法,下限可以使用线段树精细维护最大最小值达到。
很显然这不是正解,发现我们做法中有一个思想,叫做每一次染色之后都有可能存在新的区间可以染色,稍加思考发现很像拓扑,但是我们不能让询问区间向询问区间连边,因为它们之间不存在包含关系,所以存在的最朴素的做法就是对于每一个节点挂在所有在这个区间里面的节点上,然后就可以跑拓扑了。
很显然这个时间复杂度依旧会超时,发现我们是将每一个在这个区间内的点挂上这个区间,所以可以使用线段树把这个节点挂上去,每一次修改就是 \(O(\log n)\) 的,而且对于每一个线段树上的节点只会更新一次,每一个询问区间可以拉成 \(\log n\) 个节点,而且每一个节点可以使用并查集维护是否被修改过,所以均摊时间复杂度是 \(O((N+M)\log_2 N)\) 的。
做法
将每一个询问区间放到线段树上,然后类似拓扑将可以直接染色的点放在队里里面,每一次取出队头然后将队头的区间的所有点都染色,使用并查集维护所有没有被染色的节点。对于每一次修改,找到这个节点在线段树上的所有祖先然后将他们修改用类似拓扑排序的方式把可以被压队的放到队内,然后如果到最后有位置没有被染色或者有操作没有使用就无解,否则将拓扑序反转就是解
代码
#include<algorithm>
#include<iostream>
#include<cstring>
#include<climits>
#include<stdio.h>
#include<vector>
#include<cmath>
#include<queue>
#pragma GCC optimize(3,"Ofast","inline")
#define ll long long
using namespace std;
namespace ZYQIO{
const int L=1<<20;
inline char gc(){
static char buf[L],*l=buf,*r=buf;
if(l==r)r=(l=buf)+fread(buf,1,L,stdin);
return (l==r)?EOF:*l++;
}
char obuf[L],*p=obuf;
inline void pc(char c){
if(p==obuf+L)
fwrite(obuf,1,L,stdout),p=obuf;
*p++=c;
}
inline void flush(){fwrite(obuf,1,p-obuf,stdout);}
struct Reader{
template<typename T>
inline Reader& operator>>(T& x){
x=0;
short f=1;
char c=gc();
while(!isdigit(c)){
if(c=='-')
f=-1;
c=gc();
}
while(isdigit(c))x=10*x+(c-'0'),c=gc();
x*=f;
return *this;
}
Reader(){}
}cin;
struct Writer{
template<typename T>
inline Writer& operator<<(T x){
if(x < 0)pc('-'),x=-x;
static short tp=0,s[40];
do s[++tp]=x%10,x/=10;
while(x);
while(tp)pc(s[tp--] + '0');
return *this;
}
inline Writer& operator<<(const char* s){
int i=0;
while(s[i])pc(s[i++]);
return *this;
}
inline Writer& operator<<(char c){
pc(c);
return *this;
}
Writer(){}
~Writer(){flush();}
}cout;
}
#define cin ZYQIO::cin
#define cout ZYQIO::cout
#define P pair<int,int>
#define fi first
#define se second
queue<int>topo;
const int N=5e5+9;
int n,m,d[N],a[N],vis[N];
int ql[N],qr[N],qc[N];
struct node{
int lt,rt;
int cnt,col;
vector<P>que;
};
struct SGT{
#define lson(x) (x<<1)
#define rson(x) (x<<1|1)
node tr[N<<2];
inline void pushup(int id){
if(tr[lson(id)].cnt>=2 || tr[rson(id)].cnt>=2 || (tr[lson(id)].cnt==1 && tr[rson(id)].cnt==1 && tr[lson(id)].col!=tr[rson(id)].col))
return tr[id].cnt=2,tr[id].col=0,void();
if(tr[lson(id)].cnt==1) return tr[id].cnt=1,tr[id].col=tr[lson(id)].col,void();
if(tr[rson(id)].cnt==1) return tr[id].cnt=1,tr[id].col=tr[rson(id)].col,void();
tr[id].col=0;tr[id].cnt=0;
return void();
}
inline void build(int id,int l,int r){
tr[id].lt=l;tr[id].rt=r;
if(l==r)return tr[id].cnt=1,tr[id].col=a[l],void();
int mid=l+r>>1;
build(lson(id),l,mid);
build(rson(id),mid+1,r);
pushup(id);
}
inline void change_add(int id,int l,int r,int num){
if(tr[id].lt>=l && tr[id].rt<=r){
tr[id].que.push_back({num,0});
d[num]++;
return void();
}
int mid=tr[id].lt+tr[id].rt>>1;
if(l<=mid) change_add(lson(id),l,r,num);
if(mid<r) change_add(rson(id),l,r,num);
}
inline void topo_push(int id){
if(tr[id].cnt==0){
for(auto &i:tr[id].que){
if(i.se==0){
--d[i.fi];i.se=1;
if(!vis[i.fi] && d[i.fi]==0){
topo.push(i.fi);
vis[i.fi]=1;
}
}
}
}
if(tr[id].cnt==1){
for(auto &i:tr[id].que){
if(i.se==0 && qc[i.fi]==tr[id].col){
--d[i.fi];i.se=1;
if(!vis[i.fi] && d[i.fi]==0){
topo.push(i.fi);
vis[i.fi]=1;
}
}
}
}
}
inline void change_del(int id,int pos){
if(tr[id].lt==tr[id].rt){
tr[id].col=0;
tr[id].cnt=0;
topo_push(id);
return void();
}
int mid=tr[id].lt+tr[id].rt>>1;
if(pos<=mid) change_del(lson(id),pos);
else change_del(rson(id),pos);
pushup(id);
topo_push(id);
}
inline void topo_init(int id){
topo_push(id);
if(tr[id].lt==tr[id].rt) return void();
topo_init(lson(id));
topo_init(rson(id));
}
}seg;
int fa[N];
inline int Find(int x){return fa[x]==x?x:fa[x]=Find(fa[x]);}
vector<int>ans;
int main(){
cin>>n>>m;
for(int i=1;i<=m;i++)
cin>>ql[i]>>qr[i]>>qc[i];
for(int i=1;i<=n;i++){
cin>>a[i];
if(a[i]==0)a[i]=-1;
}
seg.build(1,1,n);
for(int i=1;i<=m;i++)
seg.change_add(1,ql[i],qr[i],i);
for(int i=1;i<=n;i++)
fa[i]=i;
seg.topo_init(1);
for(int i=1;i<=(n<<2);i++){
if(seg.tr[i].lt){
if(seg.tr[i].cnt==0){
for(auto &j:seg.tr[i].que){
if(j.se==0){
--d[j.fi];j.se=1;
if(!vis[j.fi] && d[j.fi]==0){
topo.push(j.fi);
vis[j.fi]=1;
}
}
}
}
if(seg.tr[i].cnt==1){
for(auto &j:seg.tr[i].que){
if(j.se==0 && qc[j.fi]==seg.tr[i].col){
--d[j.fi];j.se=1;
if(!vis[j.fi] && d[j.fi]==0){
topo.push(j.fi);
vis[j.fi]=1;
}
}
}
}
}
}
while(topo.size()){
int now=topo.front();
topo.pop();
ans.push_back(now);
for(int i=Find(qr[now]);i>=ql[now];i=Find(i-1)){
seg.change_del(1,i);
fa[i]=i-1;
}
}
if(ans.size()!=m || (seg.tr[1].cnt!=0 && seg.tr[1].col!=-1)) return cout<<"NE",0;
reverse(ans.begin(),ans.end());
cout<<"DA\n";
for(auto i:ans)cout<<i<<' ';
return 0;
}

浙公网安备 33010602011771号