[BZOJ4383][POI2015]Pustynia (拓扑排序)

来源:互联网 发布:cf一键鬼跳宏设置数据 编辑:程序博客网 时间:2024/05/18 01:52

题意:给定一个长度为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;}


1 0