zoukankan      html  css  js  c++  java
  • @bzoj


    @description@

    给定一个长度为 n 的正整数序列 a,每个数都在 1 到 10^9 范围内。
    告诉你其中 s 个数,并给出 m 条信息,每条信息包含三个数 l, r, k 以及 k 个正整数,表示 a[l], a[l+1], ..., a[r-1], a[r] 里这 k 个数中的任意一个都比任意一个剩下的 r-l+1-k 个数大(严格大于,即没有等号)。
    请任意构造出一组满足条件的方案,或者判断无解。

    input
    第一行包含三个正整数 n, s, m (1<=s<=n<=100000,1<=m<=200000)。
    接下来s行,每行包含两个正整数 p[i], d[i] (1<=p[i]<=n,1<=d[i]<=10^9),表示已知 a[p[i]]=d[i],保证 p[i] 递增。
    接下来m行,每行一开始为三个正整数 l[i], r[i], k[i] (1<=l[i]<r[i]<=n,1<=k[i]<=r[i]-l[i]),接下来 k[i] 个正整数 x[1], x[2], ..., x[k[i]] (l[i]<=x[1]<x[2]<...<x[k[i]]<=r[i]),表示这 k[i] 个数中的任意一个都比任意一个剩下的 r[i]-l[i]+1-k[i] 个数大。Σk <= 300,000

    output
    若无解,则输出NIE。
    否则第一行输出TAK,第二行输出 n 个正整数,依次输出序列 a 中每个数。

    sample input
    5 2 2
    2 7
    5 3
    1 4 2 2 3
    4 5 1 4
    sample output
    TAK
    6 7 1000000000 6 3

    @solution@

    首先不考虑任何时间会炸空间会炸等种种问题,这是一道差分约束题。
    然后我们来优化一下。

    其一是建图的时候,边的数量过多这一问题,我们使用线段树来优化建图。

    其二则是数据太大跑最短路跑不过的问题。我们根据图的特殊性来优化。
    对于我们建出的图,会产生两类环:

    第一类是源点连入某个点再由这个点连回来的情况,含义是一个数的上下界。
    这种情况,我们可以仅保留它的下界(或者是上界,看差分约束的具体实现方法),事后再来判断它的上界是否合法。

    第二类是不经过源点的环,这个环必然无解(因为它表示 a > b > c > ... > a,而这显然是不可能的)。

    综上,我们可以将这个图改成无环的图。
    然后就可以拓扑排序了。

    @accepted code@

    为了防止它溢出,我判断上界 10^9 是在拓扑排序里面判断的。

    #include<cstdio>
    #include<algorithm>
    using namespace std;
    const int MAXN = 100000;
    const int MAXM = 200000;
    const int MAXK = 300000;
    const int MAXV = 4*MAXN + MAXK;
    const int INF = int(1E9);
    struct edge{
    	int to, dis;
    	edge *nxt;
    }edges[20*MAXK + 10*MAXN + 5], *adj[MAXV + 5], *ecnt=&edges[0];
    void addedge(int u, int v, int w) {
    	edge *p = (++ecnt);
    	p->to = v, p->dis = w, p->nxt = adj[u], adj[u] = p;
    	//printf("(%d %d %d)
    ", u, v, w);
    }
    int id[MAXN + 5], num[4*MAXN + 5], cnt;
    void build_segtree(int x, int l, int r) {
    	num[x] = (++cnt);
    	if( l == r ) {
    		id[l] = num[x];
    		return ;
    	}
    	int mid = (l + r) >> 1;
    	build_segtree(x<<1, l, mid);
    	addedge(num[x<<1], num[x], 0);
    	build_segtree(x<<1|1, mid + 1, r);
    	addedge(num[x<<1|1], num[x], 0);
    }
    void build_edge_segment(int x, int l, int r, int pl, int pr, int p) {
    	if( pl <= l && r <= pr ) {
    		addedge(num[x], p, 0);
    		return ;
    	}
    	if( pl > r || pr < l )
    		return ;
    	int mid = (l + r) >> 1;
    	build_edge_segment(x<<1, l, mid, pl, pr, p);
    	build_edge_segment(x<<1|1, mid + 1, r, pl, pr, p);
    }
    int x[MAXN + 5], key[MAXN + 5], n;
    int ind[MAXV + 5], dis[MAXV + 5], stk[MAXV + 5], tp;
    void solve() {
    	for(int i=0;i<=cnt;i++) {
    		for(edge *p=adj[i];p;p=p->nxt)
    			ind[p->to]++;
    		dis[i] = INF;
    	}
    	dis[0] = 0; stk[++tp] = 0;
    	while( tp ) {
    		int t = stk[tp--];
    		for(edge *p=adj[t];p;p=p->nxt) {
    			dis[p->to] = min(dis[p->to], dis[t] + p->dis);
    			if( dis[p->to] < -INF ) {
    				puts("NIE");
    				return ;
    			}
    			ind[p->to]--;
    			if( ind[p->to] == 0 ) stk[++tp] = p->to;
    		}
    	}
    	for(int i=0;i<=cnt;i++)
    		if( ind[i] ) {
    			puts("NIE");
    			return ;
    		}
    	for(int i=1;i<=n;i++)
    		if( key[i] != -1 && key[i] + dis[id[i]] ) {
    			puts("NIE");
    			return ;
    		}
    	puts("TAK");
    	for(int i=1;i<=n;i++)
    		printf("%d%c", -dis[id[i]], (i == n) ? '
    ' : ' ');
    }
    int main() {
    	int s, m;
    	scanf("%d%d%d", &n, &s, &m);
    	build_segtree(1, 1, n);
    	for(int i=1;i<=n;i++) {
    		addedge(0, id[i], -1);
    		key[i] = -1;
    	}
    	for(int i=1;i<=s;i++) {
    		int p, d; scanf("%d%d", &p, &d);
    		addedge(0, id[p], -d);
    		key[p] = d;
    	}
    	for(int i=1;i<=m;i++) {
    		int l, r, k; cnt++;
    		scanf("%d%d%d", &l, &r, &k);
    		x[0] = l - 1, x[k + 1] = r + 1;
    		for(int j=1;j<=k;j++) scanf("%d", &x[j]);
    		for(int j=1;j<=k+1;j++) build_edge_segment(1, 1, n, x[j-1] + 1, x[j] - 1, cnt);
    		for(int j=1;j<=k;j++) addedge(cnt, id[x[j]], -1);
    	}
    	solve();
    }
    

    @details@

    什么?题目中还要求了它不能超过 10^9?
    我一开始并没有看到 QAQ。调了好久啊 QAQ。

  • 相关阅读:
    [Java]去除html中的标签或者元素属性(正则表达式)
    一份非常完整的 MySQL 规范
    前端统计图 echarts 实现简单柱状图
    获取一个表中的字段总数(mysql) Navicat如何导出Excel格式表结构 获取某个库中的一个表中的所有字段和数据类型
    【学习笔记】splay入门(更新中)
    【题解】P1972 [SDOI2009]HH的项链
    【题解】P2024 [NOI2001]食物链
    【题解】P1291 百事世界杯之旅
    【题解】P2602 数字计数
    【题解】P2831 愤怒的小鸟
  • 原文地址:https://www.cnblogs.com/Tiw-Air-OAO/p/10359111.html
Copyright © 2011-2022 走看看