首页 > 其他分享 >Luogu P8890

Luogu P8890

时间:2023-05-08 15:14:41浏览次数:48  
标签:点亮 int Luogu sum mn nd add P8890

题面

注意到直接根据题目的条件判断树是否美丽并不容易。考虑未被点亮的点,可以发现一棵树是美丽的当且仅当未被点亮的点形成一个连通块

有一个结论是,对于一个森林,点数减边数等于连通块的个数。\((*)\)

因此树是美丽的当且仅当 “未被点亮的节点的个数”减去“两端都未被点亮的边的个数” \(=1\)。令 \(P\) 表示这个值,当且仅当 \(P=1\) 时树是美丽的。

同时根据 \(*\) 结论,树上被点亮的连通块的个数就是 “被点亮的节点的个数”减去“两段都被点亮的边的个数”。设这个值为 \(Q\)。

如果我们按顺序执行点亮操作,那么每个时刻的 \(P\) 和 \(Q\) 会分别形成一个序列。更准确地说,令 \(p_i\) 表示点亮完第 \(a_i\) 个点后的 \(P\) 值,\(q_i\) 表示点亮完第 \(a_i\) 个点后的 \(Q\) 值,我们就得到了 \(p\) 和 \(q\) 两个序列,答案即为 \(\sum\limits_{i=1}^{n-1}q_i\times[p_i=1]\)。(\([X]\) 当 \(X\) 为真时 \(=1\),否则 \(=0\))

接下来考虑 link-cut 操作,先考虑断掉一条边 \((u,v)\) 时对 \(p\) 和 \(q\) 的影响:由于一个节点是否点亮只决定于 \(i\),所以边的情况不会影响点的情况。记 \(t_i\) 表示点 \(i\) 被点亮的时刻,则 \((u,v)\) 脱离“两端都未被点亮”状态的时刻就是 \(\min(t_u, t_v)\),在这之前它都对 \(p\) 有贡献,因此删去它后会使 \(p\) 的 \([1, \min(t_u, t_v) - 1]\) 区间每个数 \(+1\)。它变成“两端都被点亮”的状态的时刻是 \(\max(t_u, t_v)\),在这之后它都对 \(q\) 有贡献,因此删去它后会使 \(q\) 的 \([\max(t_u, t_v),n-1]\) 区间每个数 \(-1\)。

同理,如果连上一条边 \((x,y)\),则它会使 \(p\) 的 \([1,\min(t_x,t_y)-1]\) 区间 \(-1\),\(q\) 的 \([\max(t_x,t_y),n-1]\) 区间 \(+1\)。

于是转化成了一个线段树问题。具体地,对于线段树每个节点 \([l, r]\),维护 \(mn=\min\limits_{i=l}^rp_i\),\(cnt = \sum\limits_{i=l}^r[p_i=mn]\) 和 \(sum = \sum\limits_{i=l}^rq_i\times[p_i=mn]\) 以及加法标记即可。

时间复杂度 \(O((n+m)\log n)\)。

#include<bits/stdc++.h>
#define endl '\n'
#define rep(i, s, e) for(int i = s, i##E = e; i <= i##E; ++i)
#define per(i, s, e) for(int i = s, i##E = e; i >= i##E; --i)
#define F first
#define S second
#define int ll
#define gmin(x, y) (x = min(x, y))
#define gmax(x, y) (x = max(x, y))
using namespace std;
typedef long long ll;
typedef unsigned long long ull;
typedef long double f128;
typedef pair<int, int> pii;
constexpr int N = 5e5 + 5;
int n, m, a[N], t[N];
struct edge {
    int u, v;
} e[N];
struct node {
    int mn, sum, cnt, t1, t2;
} nd[N * 4];
#define ls (p << 1)
#define rs (p << 1 | 1)
void upd(int p, int v, int w) {
    nd[p].mn += v;
    nd[p].t1 += v;
    nd[p].sum += nd[p].cnt * w;
    nd[p].t2 += w;
}
void pushdown(int p) {
    if(nd[p].t1 || nd[p].t2) {
        upd(ls, nd[p].t1, nd[p].t2);
        upd(rs, nd[p].t1, nd[p].t2);
        nd[p].t1 = nd[p].t2 = 0;
    }
}
void pushup(int p) {
    if(nd[ls].mn < nd[rs].mn) nd[p].mn = nd[ls].mn, nd[p].sum = nd[ls].sum, nd[p].cnt = nd[ls].cnt;
    else if(nd[ls].mn > nd[rs].mn) nd[p].mn = nd[rs].mn, nd[p].sum = nd[rs].sum, nd[p].cnt = nd[rs].cnt;
    else nd[p].mn = nd[ls].mn, nd[p].sum = nd[ls].sum + nd[rs].sum, nd[p].cnt = nd[ls].cnt + nd[rs].cnt;
}
void build(int p, int l, int r) {
    if(l == r) {
        nd[p].mn = n - l;
        nd[p].sum = l;
        nd[p].cnt = 1;
        return;
    }
    int mid = (l + r) / 2;
    build(ls, l, mid), build(rs, mid + 1, r);
    pushup(p);
}
void add(int p, int l, int r, int ql, int qr, int v, int w) {
    if(l > qr || r < ql) return;
    if(ql <= l && qr >= r) return upd(p, v, w);
    pushdown(p);
    int mid = (l + r) / 2;
    add(ls, l, mid, ql, qr, v, w);
    add(rs, mid + 1, r, ql, qr, v, w);
    pushup(p);
}
signed main() {
#ifdef ONLINE_JUDGE
    ios::sync_with_stdio(0);
    cin.tie(0), cout.tie(0);
#endif
    cin >> n >> m;
    build(1, 1, n - 1);
    rep(i, 1, n - 1) cin >> e[i].u >> e[i].v;
    rep(i, 1, n - 1) cin >> a[i], t[a[i]] = i;
    t[1] = n;
    rep(i, 1, n - 1) {
        int u = e[i].u, v = e[i].v;
        add(1, 1, n - 1, 1, min(t[u], t[v]) - 1, -1, 0);
        add(1, 1, n - 1, max(t[u], t[v]), n - 1, 0, -1);
    }
    cout << (nd[1].mn == 1 ? nd[1].sum : 0) << endl;
    while(m--) {
        int u, v, x, y;
        cin >> u >> v >> x >> y;
        add(1, 1, n - 1, 1, min(t[u], t[v]) - 1, 1, 0);
        add(1, 1, n - 1, max(t[u], t[v]), n - 1, 0, 1);
        add(1, 1, n - 1, 1, min(t[x], t[y]) - 1, -1, 0);
        add(1, 1, n - 1, max(t[x], t[y]), n - 1, 0, -1);
        cout << (nd[1].mn == 1 ? nd[1].sum : 0) << endl;
    }
    return 0;
}

标签:点亮,int,Luogu,sum,mn,nd,add,P8890
From: https://www.cnblogs.com/untitled0/p/luogu-P8890.html

相关文章

  • Luogu1772 [ZJOI2006] 物流运输
    传送门简化题意给你$m$个码头,码头之间有双向边连接,$n$天,其中一些码头在某些天会不可用,这$n$天都要有一条从$1$到$m$的路,每一次更换道路会需要$k$的代价,求这$n$天每天从$1$到$m$的距离之和与更改道路的价值之和的最小值。Solution首先我们能想到一个贪心的策......
  • [Luogu-P1007]题解(C++)
    PartIPreface原题目(Luogu)PartIISketch给定一个正整数\(L\),表示独木桥长度。给定一个正整数\(N\),表示桥上士兵的数量。给定\(N\)个整数,分别表示每个士兵的坐标。规定走到\(0\)坐标或\(L+1\)的位置为下桥,两个士兵相遇时不能走过去,他们会各自回头走。求出所有士......
  • Luogu P2973 [USACO10HOL]Driving Out the Piggies G
    发现答案其实与这个点炸弹经过的次数有关,因为只要知道了这个点炸弹经过次数\(w\),这个点答案就能算出:\(w\times\frac{p}{q}\)就想到设\(f_u\)为\(u\)点炸弹经过次数\(u\)点经过次数便可以由有连边的\(v\)点推来,要满足\(v\)点此时炸弹没爆炸且\(deg_v\)条边中选了\(......
  • Luogu P1298 最接近的分数 做题记录
    算是水紫,不过也学到一些有用的东西。题意给定正小数\(N\)。求分子不大于\(n\),分母不大于\(m\)的分数\(\dfrac{n}{m}\),使得\(\dfrac{n}{m}\)的值与\(N\)最接近(这里的最接近指的是\(|\dfrac{n}{m}-N|\)最小)。分析首先,大部分人都可以想到一个暴力:枚举\(i\in[1,......
  • Luogu P8007
    Upd.2022.2.3代码写的太烂,删了(题目传送门这题如果不仔细分析的话,很容易被当成DP白白浪费很多时间(就像我)。首先根据题意,可以认为左右括号是一种相互“抵消”的关系:对于每个左括号,它右面总要有且仅有一个对应的右括号与其配对,才能使其成为一个合法括号序列。在已知序列不无限......
  • Luogu P8496
    题面场外菜鸡whker听说你谷添加国赛新题立刻前来围观首先我们看到本题对于众数的定义,很容易想到通过权值线段树求解。(类似这题,但本题不需要可持久化)对于一个序列,我们维护一个deque和一个动态开点权值线段树。deque表示序列本身,线段树每个节点记录值在\([l,r]\)中的元素......
  • Luogu P3336
    因为我也是看了大佬的题解才写的(第一问),自认为自己讲得不可能比他们再好了,但是因为好多第二问的题解都被hack了,所以这里详细讲一下第二问的正确做法。初中平几课堂开课啦其实思路很简单,利用贪心的思想,能往上走就往上走,能走多高就走多高,来看这个图:点\(A\)是当前点,点\(B\)是......
  • Luogu P1999
    题目传送门初中数学老师在平面几何的第一节课就和我们说过:点动成线,线动成面,面动成体。即,由\(i-1\)维元素变化到\(i\)维的过程,就可以认为是将\(i-1\)维物体沿第\(i\)个方向平移的过程。因此我们考虑一个二维的正方形平移得到三维的正方体的过程:如果我们以平面的个......
  • Luogu_P1613 跑路 题解
    发现和最短路差不多,不过不能朴素的跑最短路。考虑对于每两个相隔\(2\)的整数次幂的点建边,在这个新图上跑最短路就是答案。设\(f_{i,j,k}\)表示从点\(i\)跳\(2^k\)步能否到点\(j\),转移方程就是一个普通的倍增。如果点\(i\)和点\(j\)可以一步到达,那么就在新图上建一条......
  • luogu P3308 [SDOI2014]LIS
    题面传送门涨知识了,第一次知道网络流删边不用全图重跑。首先我们先跑一个暴力dp,出\(f_i\)表示以\(i\)结尾的最长上升子序列长度。然后我们将其按照这个dp值分层,相......