题意:给定一个长度为n的正整数序列a,每个数都在1到10^9范围内,告诉你其中s个数,并给出m条信息,每条信息包含三个数l,r,k以及接下来k个正整数,表示a[l]…a[r]里这k个数中的任意一个都比任意一个剩下的r-l+1-k个数大。任意构造出一组满足条件的方案,或者判断无解。n<=10w, m<=20w, k的和<=30w。
定义一条有向边(u,v,w)表示a[u]-w>=a[v],对于每条信息,枚举属于那k个数中的某个数i向每个不在那k个数当中的数连一条权值为1的边。跑拓扑排序DP,如果无环且合法则输出即可。但是这样连边边数是n^2的,会爆。
考虑vfk的a+b problem那套理论,由于连边的一定是一段连续的区间,我们用线段树优化构图。一开始线段树上父亲节点向儿子节点连权值为0的边,然后每次得到一条信息,抽象一个虚拟点,将K个点全部向这个虚拟点连权值为0的边。这K个点会将这个区间分成K+1段连续区间,我们对每一段连续区间在线段树上查询到logn段区间,然后虚拟点像这logn段区间连边即可。总共连的边数应该是O(n+Klogn)条,点数为O(n+m)。然后就可以跑拓扑排序了。实现的时候注意有很多细节,比如每个数的取值范围之类的。
#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<assert.h>
#define rep(i,a,b) for(int i=a;i<=b;++i)
#define erp(i,a,b) for(int i=a;i>=b;--i)
using namespace std;
const int MAXN = 100005;
int mxi = 1000000000;
const int MAXV = MAXN * 6;
inline void gmin(int&a, const int&b) { a>b?a=b:0; }
inline void gmax(int&a, const int&b) { a<b?a=b:0; }
inline int idx(int l, int r) { return (l+r) | (l!=r); }
int N, S, M, ax[MAXV], a[MAXV], ind[MAXV];
bool vis[MAXV];
void noso() { puts("NIE"); exit(0); }
inline void get(int&r)
{
char c, f=0; r=0;
do {c=getchar();if(c=='-') f=1;} while(c<'0'||c>'9');
do r=r*10+c-'0', c=getchar(); while(c>='0'&&c<='9');
if (f) r = -r;
}
struct Ed { int to, d, nxt; } e[MAXN*40];
int adj[MAXV], ec, nodecnt, vn;
void adde(int a, int b, int c) // b <= a-c
{
e[++ec].to = b;
e[ec].d = c;
e[ec].nxt = adj[a];
ind[b] ++;
adj[a] = ec;
}
void build(int L, int R)
{
int i = idx(L, R), mid = (L+R)>>1;
gmax(nodecnt, i);
if (L == R) return;
adde(i, idx(L, mid), 0);
adde(i, idx(mid+1, R), 0);
build(L, mid), build(mid+1, R);
}
void quary(int t, int l, int r, int L, int R)
{
if (L>r || R<l) return;
if (L>=l && R<=r)
{
adde(t, idx(L, R), 1);
return;
}
int mid = (L+R)>>1;
quary(t, l, r, L, mid);
quary(t, l, r, mid+1, R);
}
int que[MAXV];
void toposort()
{
int l = 1, r = 0, u, v;
rep(i, 1, vn) if (!ind[i]) que[++r] = i;
if (a[idx(1, N)]==-1) a[idx(1, N)] = mxi;
while (l <= r)
{
u = que[l++];
vis[u] = 1;
for (int i = adj[u]; i; i=e[i].nxt)
{
v = e[i].to;
if (~a[v]) gmin(a[v], a[u] - e[i].d);
else a[v] = a[u] - e[i].d;
if (ax[v] && a[v] < ax[v]) noso();
if (!--ind[v]) que[++r] = v;
}
}
}
int main()
{
get(N), get(S), get(M);
build(1, N), vn = nodecnt;
memset(a, -1, sizeof a);
int p, d, l, r, K;
rep(i, 1, S)
{
get(p), get(d);
if (ax[idx(p, p)] && ax[idx(p, p)]!=d) noso();
ax[idx(p, p)] = a[idx(p, p)] = d;
}
rep(i, 1, M)
{
get(l), get(r), get(K);
++vn, que[1] = l - 1;
rep(j, 2, K+1)
{
get(que[j]);
adde(idx(que[j], que[j]), vn, 0);
}
que[K+2] = r + 1;
rep(j, 2, K+2)
{
l = que[j-1]+1, r = que[j]-1;
if (l <= r) quary(vn, l, r, 1, N);
}
}
toposort();
rep(i, 1, N) if (!vis[idx(i, i)] || a[idx(i, i)]<1) noso();
puts("TAK");
rep(i, 1, N) printf("%d%c", a[idx(i, i)], i!=N?' ':'\n');
return 0;
}