其实就是一些大小关系。我们设一条边 u→v u → v 代表 u>v u > v 或者 u≤v u ≤ v ,这要看具体情况,或者说分两类。对于每个限制,我们可以开一个虚点,每个大的向虚点连一条 ≤ ≤ 的边,然后发现虚点会向若干段连续区间连边,直接线段树优化连边就好了。最后填数时,倒过来贪心,深度越深,就贪心取越小。其实这就是一个DAG上的dp。
在xsy过了,在lydsy上因常数过大TLE了。。。
#include
#include
#include
#include
#include
#pragma GCC optimize(3)
using namespace std;
const int N=100005,M=1000005;
int n,s,m,p,d,l,r,k,cnt,tot,rt,x[N],f[M],ch[M][2],in[M],pos[M];
bool vis[M],ck[M];
queue<int> q;
vector<int> e1[M],e2[M];
void adde(int u,int v){
e1[u].push_back(v);
in[v]++;
e2[v].push_back(u);
}
void build(int &o,int l,int r){
o=++tot;
if(l==r){
adde(o,l);
return;
}
int mid=(l+r)/2;
build(ch[o][0],l,mid);
build(ch[o][1],mid+1,r);
adde(o,ch[o][0]);
adde(o,ch[o][1]);
}
void update(int o,int l,int r,int L,int R,int v){
if(L<=l&&R>=r){
adde(v,o);
return;
}
int mid=(l+r)/2;
if(L<=mid){
update(ch[o][0],l,mid,L,R,v);
}
if(R>mid){
update(ch[o][1],mid+1,r,L,R,v);
}
}
int main(){
scanf("%d%d%d",&n,&s,&m);
for(int i=1;i<=s;i++){
scanf("%d%d",&p,&d);
f[p]=d;
ck[p]=true;
}
tot=n;
build(rt,1,n);
for(int i=1;i<=m;i++){
scanf("%d%d%d",&l,&r,&k);
tot++;
for(int j=1,last=l-1;j<=k;last=x[j],j++){
scanf("%d",&x[j]);
adde(x[j],tot);
if(last+11,n,last+1,x[j]-1,tot);
}
}
if(x[k]1,n,x[k]+1,r,tot);
}
}
for(int i=1;i<=tot;i++){
if(!in[i]){
q.push(i);
}
}
while(!q.empty()){
int u=q.front(),v;
q.pop();
pos[++pos[0]]=u;
vis[u]=true;
for(int i=0;i<(int)e1[u].size();i++){
v=e1[u][i];
in[v]--;
if(!in[v]){
q.push(v);
}
}
}
for(int i=pos[0];i>=1;i--){
if(!f[pos[i]]){
f[pos[i]]=1;
}
for(int j=0;j<(int)e2[pos[i]].size();j++){
int v=e2[pos[i]][j];
if(pos[i]<=n){
if(ck[v]){
if(f[pos[i]]+1>f[v]){
puts("NIE");
return 0;
}
}else{
f[v]=max(f[v],f[pos[i]]+1);
}
}else{
if(ck[v]){
if(f[pos[i]]>f[v]){
puts("NIE");
return 0;
}
}else{
f[v]=max(f[v],f[pos[i]]);
}
}
}
}
for(int i=1;i<=n;i++){
if(!vis[i]||f[i]>1000000000||f[i]<1){
puts("NIE");
return 0;
}
}
puts("TAK");
for(int i=1;i<=n;i++){
printf("%d ",f[i]);
}
puts("");
return 0;
}