传送门
Description
给定一个长度为n的正整数序列aaa,每个数都在111到10910^9109范围内,告诉你其中sss个数,并给出mmm条信息,每条信息包含三个数l,r,kl,r,kl,r,k以及接下来kkk个正整数x1,x2,...,xkx_1,x_2,...,x_kx1,x2,...,xk,表示a[l],a[l+1],...,a[r−1],a[r]a[l],a[l+1],...,a[r-1],a[r]a[l],a[l+1],...,a[r−1],a[r]里 a[x1],a[x2],...,a[xk]a[x_1],a[x_2],...,a[x_k]a[x1],a[x2],...,a[xk]这kkk个数中的任意一个 都比 剩下的r−l+1−kr-l+1-kr−l+1−k个数中的任意一个大(严格大于,即没有等号)。
请任意构造出一组满足条件的方案,或者判断无解。
Solution
差分约数系统+线段树优化建图+按拓扑序DP
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
const int N=1e5+10;
struct Edge{int v,w;};
vector<Edge> g[N*10];
int tot,rt,ls[N*10],rs[N*10],id[N],a[N*10],dis[N*10],in[N*10];
queue<int> q;
int n,s,m;
void add(int u,int v,int w){g[u].push_back((Edge){v,w});in[v]++;
}
void build(int &u,int l,int r){u=++tot;if(l==r){id[l]=u;return;}int mid=(l+r)>>1;build(ls[u],l,mid);build(rs[u],mid+1,r);add(ls[u],u,0);add(rs[u],u,0);
}
void update(int u,int l,int r,int ql,int qr){if(ql>qr) return;if(ql<=l&&r<=qr){add(u,tot,0);return;}int mid=(l+r)>>1;if(ql<=mid) update(ls[u],l,mid,ql,qr);if(qr>mid) update(rs[u],mid+1,r,ql,qr);
}
int main(){scanf("%d%d%d",&n,&s,&m);build(rt,1,n);for(int i=1;i<=s;i++){int p,d;scanf("%d%d",&p,&d);a[id[p]]=d;}for(int i=1;i<=m;i++){int l,r,k,x,lst;scanf("%d%d%d",&l,&r,&k);tot++;lst=l-1;for(int j=1;j<=k;j++){scanf("%d",&x);add(tot,id[x],1);update(1,1,n,lst+1,x-1);lst=x;}update(1,1,n,lst+1,r);}for(int i=1;i<=tot;i++){if(in[i]==0){dis[i]=1;q.push(i);}}int t=0;while(!q.empty()){int u=q.front();q.pop();t++;if(dis[u]>1000000000) return puts("NIE"),0;if(a[u]&&dis[u]>a[u]) return puts("NIE"),0;dis[u]=max(dis[u],a[u]);for(int i=0;i<g[u].size();i++){int v=g[u][i].v,w=g[u][i].w;dis[v]=max(dis[u]+w,dis[v]);in[v]--;if(in[v]==0) q.push(v);}}if(t<tot) return puts("NIE"),0;puts("TAK");for(int i=1;i<=n;i++) printf("%d ",dis[id[i]]);return 0;
}