zoukankan      html  css  js  c++  java
  • 洛谷P3241 开店

    题意:紫妹和幽香是17岁的少女,喜欢可爱的东西。

    给定一棵树,有点权,边权。每次求所有权值在[l, r]范围内的点到点x的距离和。强制在线。

    解:动态点分治怎么搞啊......

    一开始想的是权值的限制直接外层权值线段树就行了,关键是怎么批量求距离。

    jxl想的是树上莫队的方法,括号序列。然后发现当x和y在不同子树的时候,x -> lca的距离是负的。

    然后考虑lca。距离是d[x] + d[y] - 2d[lca],前面两个都好求,主要是第三项。

    稍稍思考一下,lca只可能是x到根路径上的点。每个点作为lca的次数就是siz - siz[son]

    所以可以转为计算每条边的贡献。每条边的贡献就是它下面的子树大小。这样就可以做了。

    具体来说,d[x] * cnt和∑d[y]可以用两个前缀和数组求出。以离散化后的权值为下标。

    然后建一个以权值为版本的主席树,线段树上维护的是DFS序的该点的父边的计算次数。

    可以发现,按照权值我们每插入一个点,就要对它到根的路径进行修改。查询的时候也是查询x到根的路径。所以我们必须写树剖了>_<

    主席树区间加区间查,使用标记永久化。

    然后发现我之前以为的标记永久化都是假的......

    具体来说,给一个区间加的时候,它途中经过的区间都要加上相应的值,而标记只打在最后的区间。

    查询的时候,沿途记录标记数量。到终点的时候,用终点的sum + 区间Val * 标记数量即可。

    如果修改在查询上面,那么你会把标记记录下来,最后在终点区间加上。

    如果修改在下,那么你终点区间的sum已经加了那一次修改的影响。

    然后这道毒瘤SB题就这样A了...时间复杂度nlog2n。

      1 #include <cstdio>
      2 #include <algorithm>
      3 
      4 typedef long long LL;
      5 const int N = 150010, lm = 1e9, M = 30000010;
      6 
      7 struct Edge {
      8     int nex, v, len;
      9 }edge[N << 1]; int tp;
     10 
     11 struct Node {
     12     int val, p;
     13     inline bool operator <(const Node &w) const {
     14         return val < w.val;
     15     }
     16 }node[N];
     17 
     18 int e[N], n, top[N], son[N], fa[N], pos[N], num, siz[N], X[N], deep[N], Sum[N], id[N], val2[N], tot, rt[N], val[N];
     19 LL Val[M], d[N], exVal[N];
     20 int ls[M], rs[M], exsum[N], tag[M];
     21 
     22 inline void add(int x, int y, int z) {
     23     tp++;
     24     edge[tp].v = y;
     25     edge[tp].len = z;
     26     edge[tp].nex = e[x];
     27     e[x] = tp;
     28     return;
     29 }
     30 
     31 void DFS_1(int x, int f) { // siz fa d son
     32     fa[x] = f;
     33     siz[x] = 1;
     34     deep[x] = deep[f] + 1;
     35     for(int i = e[x]; i; i = edge[i].nex) {
     36         int y = edge[i].v;
     37         if(y == f) {
     38             continue;
     39         }
     40         d[y] = d[x] + edge[i].len;
     41         val2[y] = edge[i].len;
     42         DFS_1(y, x);
     43         siz[x] += siz[y];
     44         if(siz[y] > siz[son[x]]) {
     45             son[x] = y;
     46         }
     47     }
     48     return;
     49 }
     50 
     51 void DFS_2(int x, int f) { // pos top
     52     top[x] = f;
     53     pos[x] = ++num;
     54     id[num] = x;
     55     if(son[x]) {
     56         DFS_2(son[x], f);
     57     }
     58     for(int i = e[x]; i; i = edge[i].nex) {
     59         int y = edge[i].v;
     60         if(y == fa[x] || y == son[x]) {
     61             continue;
     62         }
     63         DFS_2(y, y);
     64     }
     65     return;
     66 }
     67 
     68 void Add(int x, int &y, int L, int R, int l, int r) {
     69     if(!y || y == x) {
     70         y = ++tot;
     71         Val[y] = Val[x];
     72         tag[y] = tag[x];
     73         ls[y] = ls[x];
     74         rs[y] = rs[x];
     75         //printf("new %d [%d %d] val = %lld 
    ", y, l, r, Val[y]);
     76     }
     77     Val[y] += Sum[std::min(R, r)] - Sum[std::max(L, l) - 1];
     78     //printf("val %d = %lld  += (%d %d) %d 
    ", y, Val[y], std::min(R, r), std::max(L, l) - 1, Sum[std::min(R, r)] - Sum[std::max(L, l) - 1]);
     79     if(L <= l && r <= R) {
     80         tag[y]++;
     81         return;
     82     }
     83     int mid = (l + r) >> 1;
     84     if(L <= mid) {
     85         Add(ls[x], ls[y], L, R, l, mid);
     86     }
     87     if(mid < R) {
     88         Add(rs[x], rs[y], L, R, mid + 1, r);
     89     }
     90     return;
     91 }
     92 
     93 inline void insert(int x, int id) {
     94     while(x) {
     95         //printf("id = %d 
    ", id);
     96         Add(rt[id - 1], rt[id], pos[top[x]], pos[top[x]] + (deep[x] - deep[top[x]]), 1, n);
     97         x = fa[top[x]];
     98     }
     99     return;
    100 }
    101 
    102 LL Ask(int x, int y, int L, int R, int l, int r, int tagx, int tagy) {
    103     if(L <= l && r <= R) {
    104         return Val[y] - Val[x] + 1ll * (tagy - tagx) * (Sum[r] - Sum[l - 1]);
    105     }
    106     tagx += tag[x];
    107     tagy += tag[y];
    108     int mid = (l + r) >> 1;
    109     LL ans = 0;
    110     if(L <= mid) {
    111         ans += Ask(ls[x], ls[y], L, R, l, mid, tagx, tagy);
    112     }
    113     if(mid < R) {
    114         ans += Ask(rs[x], rs[y], L, R, mid + 1, r, tagx, tagy);
    115     }
    116     return ans;
    117 }
    118 
    119 LL ask(int l, int r, int x) {
    120     LL ans = 0;
    121     while(x) {
    122         LL t = Ask(rt[l - 1], rt[r], pos[top[x]], pos[top[x]] + (deep[x] - deep[top[x]]), 1, n, 0, 0);
    123         ans += t;
    124         x = fa[top[x]];
    125     }
    126     return ans;
    127 }
    128 
    129 int main() {
    130 
    131     //freopen("in.in", "r", stdin);
    132     //freopen("my.out", "w", stdout);
    133 
    134     int q, A;
    135     scanf("%d%d%d", &n, &q, &A);
    136     for(int i = 1; i <= n; i++) {
    137         scanf("%d", &val[i]);
    138         val[i]++;
    139         node[i].p = i;
    140         X[i] = val[i];
    141     }
    142     for(int i = 1, x, y, z; i < n; i++) {
    143         scanf("%d%d%d", &x, &y, &z);
    144         add(x, y, z);
    145         add(y, x, z);
    146     }
    147     // prework
    148 
    149     DFS_1(1, 0);
    150     DFS_2(1, 1);
    151     std::sort(X + 1, X + n + 1);
    152     int temp = std::unique(X + 1, X + n + 1) - X - 1;
    153     for(int i = 1; i <= n; i++) {
    154         val[i] = std::lower_bound(X + 1, X + temp + 1, val[i]) - X;
    155         node[i].val = val[i];
    156         exsum[val[i]]++;
    157         exVal[val[i]] += d[i];
    158     }
    159     for(int i = 1; i <= temp; i++) {
    160         exsum[i] += exsum[i - 1];
    161         exVal[i] += exVal[i - 1];
    162     }
    163     for(int i = 1; i <= n; i++) {
    164         Sum[i] = Sum[i - 1] + val2[id[i]];
    165     }
    166     std::sort(node + 1, node + n + 1);
    167     for(int i = 1; i <= n; i++) {
    168         insert(node[i].p, node[i].val);
    169     }
    170 
    171     LL lastans = 0;
    172     for(int i = 1, x, y, z; i <= q; i++) {
    173         scanf("%d%d%d", &x, &y, &z);
    174         int l = (y + lastans) % A + 1;
    175         int r = (z + lastans) % A + 1;
    176         if(l > r) {
    177             std::swap(l, r);
    178         }
    179         l = std::lower_bound(X + 1, X + temp + 1, l) - X;
    180         r = std::upper_bound(X + 1, X + temp + 1, r) - X - 1;
    181         if(l > r) {
    182             lastans = 0;
    183             printf("%lld
    ", lastans);
    184         }
    185         else {
    186             LL t = ask(l, r, x);
    187             lastans = 1ll * d[x] * (exsum[r] - exsum[l - 1]) + (exVal[r] - exVal[l - 1]);
    188             lastans -= t * 2;
    189             printf("%lld
    ", lastans);
    190         }
    191     }
    192 
    193     return 0;
    194 }
    AC代码
  • 相关阅读:
    杭电2059
    杭电2058
    php错误大集合
    显示IP地址
    超简单好用的屏幕录像工具
    jquery“不再提醒"功能
    KindEditor编辑器中的class自动过滤了
    实用案例:切换面板同时切换内容
    仿51返利用户图解教程
    JavaScript调用dataTable并获取其值(ASP.Net,VS2005)
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10322135.html
Copyright © 2011-2022 走看看