题目大意:给出一张有向图,保证任何时候边都是从编号大的向编号小连。两个操作:
- $1;l;r:$表示若编号在区间$[l,r]$内的点被染色了,问至少还需要染多少个点才可以使得整张图被染色。一个点会被染色的要求是:要么直接被染色,要么它所连向的点中至少一个被染色
- $2;l;r;x:$表示编号在区间$[l,r]$中的所有点都向$x$连一条边,保证$x<l$
题解:发现这张图是一个$DAG$,然后只要把所有出度为$0$的点染色就一定可以把所有点染色。
于是就记录每个点是否出度为$0$,询问是区间$[1,l)cup(r,n]$中出度为$0$的点的个数,修改就把区间$[l,r]$中出度为$0$的点改为非$0$。可以用线段树维护
卡点:无
C++ Code:
#include <cstdio> #include <cctype> namespace std { struct istream { #define M (1 << 24 | 3) char buf[M], *ch = buf - 1; inline istream() { #ifndef ONLINE_JUDGE freopen("input.txt", "r", stdin); #endif fread(buf, 1, M, stdin); } inline istream& operator >> (int &x) { while (isspace(*++ch)); for (x = *ch & 15; isdigit(*++ch); ) x = x * 10 + (*ch & 15); return *this; } #undef M } cin; struct ostream { #define M (1 << 23 | 3) char buf[M], *ch = buf - 1; inline ostream& operator << (int x) { if (!x) { *++ch = '0'; return *this; } static int S[20], *top; top = S; while (x) { *++top = x % 10 ^ 48; x /= 10; } for (; top != S; --top) *++ch = *top; return *this; } inline ostream& operator << (const char x) { *++ch = x; return *this; } inline ~ostream() { #ifndef ONLINE_JUDGE freopen("output.txt", "w", stdout); #endif fwrite(buf, 1, ch - buf + 1, stdout); } #undef M } cout; } #define maxn 300010 int n, m; bool notice[maxn]; namespace SgT { bool tg[maxn << 2]; int V[maxn << 2]; void build(int rt, int l, int r) { if (l == r) { V[rt] = !notice[l]; return ; } int mid = l + r >> 1; build(rt << 1, l, mid), build(rt << 1 | 1, mid + 1, r); V[rt] = V[rt << 1] + V[rt << 1 | 1]; } int L, R; inline void pushdown(int rt) { V[rt << 1] = V[rt << 1 | 1] = 0; tg[rt << 1] = tg[rt << 1 | 1] = true; tg[rt] = false; } void __modify(const int rt, const int l, const int r) { if (L <= l && R >= r) { V[rt] = 0; tg[rt] = true; return ; } if (tg[rt]) pushdown(rt); const int mid = l + r >> 1; if (L <= mid) __modify(rt << 1, l, mid); if (R > mid) __modify(rt << 1 | 1, mid + 1, r); V[rt] = V[rt << 1] + V[rt << 1 | 1]; } void modify(const int __L, const int __R) { L = __L, R = __R; __modify(1, 1, n); } int res; void __query(const int rt, const int l, const int r) { if (L <= l && R >= r) { res += V[rt]; return ; } if (tg[rt]) pushdown(rt); const int mid = l + r >> 1; if (L <= mid) __query(rt << 1, l, mid); if (R > mid) __query(rt << 1 | 1, mid + 1, r); } int query(const int __L, const int __R) { if (__L > __R) return 0; L = __L, R = __R, res = 0; __query(1, 1, n); return res; } } int main() { std::cin >> n >> m; for (int i = 1, k; i <= n; ++i) { std::cin >> k; for (int j = 0, x; j < k; ++j) std::cin >> x, notice[x] = true; } SgT::build(1, 1, n); while (m --> 0) { static int op, l, r, x; std::cin >> op >> l >> r; if (op == 1) std::cout << SgT::query(1, l - 1) + SgT::query(r + 1, n) << ' '; else std::cin >> x, SgT::modify(l, r); } return 0; }