BZOJ4383/LuoGuP3588 Pustynia/PUS 线段树建图优化

我会告诉你我看了很久很久才把题目看懂吗???怀疑智商了

原来他给的l,r还有k个数字都是下标...

比如给了一个样例 l, r, k, x1,x2,x3...xk,代表的是一个数组num[l]~num[r],其中有k个数num[x1],num[x2]....num[xk]这k个数都比l~r区间剩下的(下标不是x1...xk)的任何一个数大。题目就是给m个这种信息然后构造一个符合条件的数列

知道了这一点可以发现每一个信息都是一组偏序关系,即num[x1] > l~r区间剩下的数 .....num[xk] > l~r区间剩下的数.当然如果数量级小的话直接就每一个关系建一条边直接拓扑排序就可以了.但是这道题数量实在太大,然后这里就有一种黑科技---线段树建图优化.因为我们可以保证每次建边的时候,num[xi]都是和一个区间相连的(单个点也算一个区间),这样我们可考虑区间这个整体,当然具体代码怎么写没这么简单.

又学到一种黑科技....

 #include <iostream>
#include <string.h>
#include <cstdio>
#include <vector>
#include <queue>
#include <math.h>
#include <string>
#include <algorithm>
#include <time.h> #define SIGMA_SIZE 26
#define lson rt<<1
#define rson rt<<1|1
#define lowbit(x) (x&-x)
#define foe(i, a, b) for(int i=a; i<=b; i++)
#define fo(i, a, b) for(int i=a; i<b; i++)
#pragma warning ( disable : 4996 ) using namespace std;
typedef long long LL;
inline LL LMax(LL a, LL b) { return a>b ? a : b; }
inline LL LMin(LL a, LL b) { return a>b ? b : a; }
inline LL lgcd(LL a, LL b) { return b == ? a : lgcd(b, a%b); }
inline LL llcm(LL a, LL b) { return a / lgcd(a, b)*b; } //a*b = gcd*lcm
inline int Max(int a, int b) { return a>b ? a : b; }
inline int Min(int a, int b) { return a>b ? b : a; }
inline int gcd(int a, int b) { return b == ? a : gcd(b, a%b); }
inline int lcm(int a, int b) { return a / gcd(a, b)*b; } //a*b = gcd*lcm
const LL INF = 0x3f3f3f3f3f3f3f3f;
const LL mod = ;
const double eps = 1e-;
const int inf = 0x3f3f3f3f;
const int maxk = 3e6+;
const int maxn = 1e6+; int cnt, tot;
int indexx[maxn], val1[maxn], val2[maxn], x[maxn], in[maxn];
int linjie[maxn];
int n, s, m;
queue<int> q;
struct node {
int to, nnext, len;
}pp[maxk]; void addedge( int u, int v, int l )
{ pp[cnt].to = v; pp[cnt].len = l; pp[cnt].nnext = linjie[u]; linjie[u] = cnt++; in[v]++; } void build(int rt, int L, int R)
{
if ( L == R )
{ indexx[L] = rt; return; } int mid = (L+R)>>;
build(lson, L, mid);
build(rson, mid+, R);
addedge(lson, rt, ); addedge(rson, rt, );
} void update(int rt, int L, int R, int lhs, int rhs, int C)
{
if ( lhs <= L && rhs >= R )
{
addedge(rt, C, );
return;
} int mid = (L+R)>>;
if ( lhs <= mid ) update(lson, L, mid, lhs, rhs, C);
if ( rhs > mid ) update(rson, mid+, R, lhs, rhs, C);
} void init()
{
cnt = ;
memset(linjie, -, sizeof(linjie));
build(, , n); tot = n << ; int a, b;
while (s--)
{
scanf("%d %d", &a, &b);
val1[indexx[a]] = val2[indexx[a]] = b;
}
} int main()
{
cin >> n >> s >> m;
init(); int l, r, k;
while (m--)
{
scanf("%d %d %d", &l, &r, &k);
x[] = l-; x[k+] = r+; tot++; foe(i, , k) {
scanf("%d", &x[i]);
addedge(tot, indexx[x[i]], );
} foe(i, , k) {
if (x[i+] - x[i] > )
update(, , n, x[i]+, x[i+]-, tot);
}
} foe(i, , tot)
if (!in[i]) {
val1[i] = Max(val1[i], );
q.push(i);
} int a, b;
while (!q.empty())
{
a = q.front(); q.pop();
for (int i = linjie[a]; ~i; i = pp[i].nnext) {
val1[pp[i].to] = Max(val1[pp[i].to], val1[a]+pp[i].len);
in[pp[i].to] --; if (val2[pp[i].to] && val1[pp[i].to] > val2[pp[i].to]) {
printf("NIE\n");
return ;
}
if ( !in[pp[i].to] )q.push(pp[i].to);
}
} foe(i, , n)
if ( !val1[indexx[i]] || val1[indexx[i]] > )
{ printf("NIE\n"); return ; } printf("TAK\n");
fo(i, , n)
printf("%d ", val1[indexx[i]]);
printf("%d\n", val1[indexx[n]]);
return ;
}
上一篇:python之旅:函数基础


下一篇:在Mac OS X中使用VIM开发STM32(2)