zoukankan      html  css  js  c++  java
  • 【线段树 扫描线 二维数点】loj#6276. 果树

    路径计数转成二维数点很妙啊

    题目描述

    NiroBC 姐姐是个活泼的少女,她十分喜欢爬树,而她家门口正好有一棵果树,正好满足了她爬树的需求。

    这颗果树有 $N$ 个节点,标号 $1 ldots N$ 。每个节点长着一个果子,第 $i$ 个节点上的果子颜色为 $C_i$​ 。

    NiroBC 姐姐每天都要爬树,每天都要选择一条有趣的路径 $(u, v)$ 来爬。

    一条路径被称作有趣的,当且仅当这条路径上的果子的颜色互不相同。

    $(u, v)$ 和 $(v, u)$ 被视作同一条路径。特殊地, $(i, i)$ 也被视作一条路径,这条路径只含 $i$ 一个节点,显然是有趣的。

    NiroBC 姐姐想知道这颗树上有多少条有趣的路径。

    输入格式

    第一行,一个整数 $N$ ,表示果树的节点数目。

    接下来一行 $N$ 个整数 $C_{1 ldots N}$ ,表示 $N$ 个果子各自的颜色。

    再接下来 $N-1$ 行,每行两个整数 $u_i, v_i$​ ,表示 $u_i$​ 和 $v_i$​ 之间有一条边。

    数据保证这 $N-1$ 条边构成一棵树。

    输出格式

    一个整数,有趣的路径的数量。

    样例

    样例输入 1

    3
    1 2 3
    1 2
    1 3

    样例输出 1

    6

    样例输入 2

    5
    1 1 2 3 3
    1 2
    1 3
    2 4
    2 5

    样例输出 2

    8

    样例解释 1

    有 $(1,1)(1,2)(1,3)(2,2)(2,3)(3,3)$ 共 $6$ 条路径。

    样例解释 2

    有 $(1,1)(1,3)(2,2)(2,4)(2,5)(3,3)(4,4)(5,5)$ 共 $8$ 条路径。

    数据范围与提示

    对于所有数据, $1 le N le 10^5$ ,$1 le C_i le N$ ,每种颜色在树上出现不超过 $20$ 次。

    本题采用打包测试。

    各个 Subtask 的特殊限制如下,不填代表该项无特殊限制。

    Subtask 编号$N$其他限制该 Subtask 分值
    0 $le 100$   12
    1 $le 3000$   25
    2   整棵树形成一条依次为 $1, 2, 3, ldots , N$ 的链 30
    3     33

    题目分析

    二维数点

    注意到每种颜色的出现次数非常小,于是考虑枚举同种颜色。

    对于颜色相同的一对点,它们会把树分成三个部分,而两端部分不能够相互连边。这个部分用dfs序把图再构一遍,就方便处理了。至于两种分别是成链不成链的情况,稍微细心点细节就没问题。

    点对$(x,y)$可以表示为二维点$(x,y)$,也就是说每一次将非法位置转为二维矩形覆盖,那么最后就是枚举每一个点,对非法矩形差分扫描线处理。

    码力还是不够,标记${ m //HERE}$都是打挂的地方。

      1 #include<bits/stdc++.h>
      2 const int maxn = 100035;
      3 const int maxm = 200035;
      4 const int maxLog = 23;
      5 
      6 struct dfn
      7 {
      8     int l,r;
      9 }a[maxn];
     10 struct node
     11 {
     12     int mn,tot,tag;
     13 }f[maxn<<2];
     14 struct line
     15 {
     16     int l,r,opt;
     17     line (int a=0, int b=0, int c=0):l(a),r(b),opt(c) {}
     18 };
     19 long long ans;
     20 int n,c[maxn],fa[maxn][maxLog],dep[maxn],chTot;
     21 int edgeTot,head[maxn],nxt[maxm],edges[maxm];
     22 std::vector<int> col[maxn];
     23 std::vector<line> mdf[maxn];
     24 
     25 int read()
     26 {
     27     char ch = getchar();
     28     int num = 0, fl = 1;
     29     for (; !isdigit(ch); ch=getchar())
     30         if (ch=='-') fl = -1;
     31     for (; isdigit(ch); ch=getchar())
     32         num = (num<<1)+(num<<3)+ch-48;
     33     return num*fl;
     34 }
     35 void addedge(int u, int v)
     36 {
     37     edges[++edgeTot] = v, nxt[edgeTot] = head[u], head[u] = edgeTot;
     38     edges[++edgeTot] = u, nxt[edgeTot] = head[v], head[v] = edgeTot;
     39 }
     40 inline int kfa(int x, int d)
     41 {
     42     if (d==-1) return x;
     43     for (int i=20; i>=0; i--)
     44         if (d>>i&1) x = fa[x][i];
     45     return x;
     46 }
     47 void addLine(int l1, int r1, int l2, int r2)
     48 {
     49     if (l1 > r1||l2 > r2) return;
     50     mdf[l1].push_back(line(l2, r2, 1));
     51     mdf[r1+1].push_back(line(l2, r2, -1));
     52     mdf[l2].push_back(line(l1, r1, 1));
     53     mdf[r2+1].push_back(line(l1, r1, -1));
     54 }
     55 inline void split(int x, int y)
     56 {
     57     if (dep[x] > dep[y]) std::swap(x, y);
     58     int anc = kfa(y, dep[y]-dep[x]-1);        //HERE
     59     if (fa[anc][0]!=x||(dep[x]==dep[y]&&x!=y)) addLine(a[x].l, a[x].r, a[y].l, a[y].r);
     60     else{
     61         addLine(1, a[anc].l-1, a[y].l, a[y].r);
     62         addLine(a[anc].r+1, n, a[y].l, a[y].r);        //HERE    这里打挂只剩链30pts
     63     }
     64 }
     65 void smcolConnect()
     66 {
     67     register int i,j,k;
     68     for (i=1; i<=n; i++)
     69         for (j=0; j<col[i].size(); j++)
     70             for (k=j+1; k<col[i].size(); k++)
     71                 split(col[i][j], col[i][k]);        //HERE
     72 }
     73 void dfs(int x, int fat)
     74 {
     75     dep[x] = dep[fat]+1, fa[x][0] = fat;
     76     a[x].l = ++chTot;
     77     for (int i=head[x]; i!=-1; i=nxt[i])
     78         if (edges[i]!=fat) dfs(edges[i], x);
     79     a[x].r = chTot;
     80 }
     81 void build(int rt, int l, int r)
     82 {
     83     f[rt].tot = r-l+1;
     84     if (l==r) return;
     85     int mid = (l+r)>>1;
     86     build(rt<<1, l, mid);
     87     build(rt<<1|1, mid+1, r);
     88 }
     89 void init()
     90 {
     91     for (int j=1; j<=20; j++)
     92         for (int i=1; i<=n; i++)
     93             fa[i][j] = fa[fa[i][j-1]][j-1];
     94     build(1, 1, n);
     95 }
     96 void pushdown(int rt)
     97 {
     98     int l = rt<<1, r = rt<<1|1, &t = f[rt].tag;
     99     if (t){
    100         f[l].tag += t, f[r].tag += t;
    101         f[l].mn += t, f[r].mn += t, t = 0;            //HERE
    102     }
    103 }
    104 void pushup(int rt)
    105 {
    106     f[rt].mn = std::min(f[rt<<1].mn, f[rt<<1|1].mn);
    107     f[rt].tot = (f[rt].mn==f[rt<<1].mn?f[rt<<1].tot:0)+(f[rt].mn==f[rt<<1|1].mn?f[rt<<1|1].tot:0);
    108 }
    109 void modify(int rt, int L, int R, int l, int r, int c)
    110 {
    111     if (L <= l&&r <= R){
    112         f[rt].mn += c, f[rt].tag += c;
    113         return;
    114     }
    115     int mid = (l+r)>>1;
    116     pushdown(rt);      //HERE
    117     if (L <= mid) modify(rt<<1, L, R, l, mid, c);
    118     if (R > mid) modify(rt<<1|1, L, R, mid+1, r, c);
    119     pushup(rt);
    120 }
    121 int main()
    122 {
    123     memset(head, -1, sizeof head);
    124     n = read();
    125     for (int i=1; i<=n; i++) c[i] = read(), col[c[i]].push_back(i);
    126     for (int i=1; i<n; i++) addedge(read(), read());
    127     dfs(1, 0), init();
    128     smcolConnect();
    129     for (int i=1; i<=n; i++)
    130     {
    131         for (unsigned int p=0; p<mdf[i].size(); p++)
    132             modify(1, mdf[i][p].l, mdf[i][p].r, 1, n, mdf[i][p].opt);
    133         if (f[1].mn==0) ans += f[1].tot;
    134     }
    135     printf("%lld
    ",(ans+n)>>1);
    136     return 0;
    137 }

    DSU做法

    还看到一种神奇的dsu+可持久化线段树做法:LibreOJ #6276.果树 dsu on tree+可持久化线段树

    END

  • 相关阅读:
    hdu acm 2844 Coins 解题报告
    hdu 1963 Investment 解题报告
    codeforces 454B. Little Pony and Sort by Shift 解题报告
    广大暑假训练1 E题 Paid Roads(poj 3411) 解题报告
    hdu acm 2191 悼念512汶川大地震遇难同胞——珍惜现在,感恩生活
    hdu acm 1114 Piggy-Bank 解题报告
    poj 2531 Network Saboteur 解题报告
    数据库范式
    ngnix 配置CI框架 与 CI的简单使用
    Vundle的安装
  • 原文地址:https://www.cnblogs.com/antiquality/p/9925210.html
Copyright © 2011-2022 走看看