• (树上莫队)HDU


    题意:

    两种询问:

    1、询问以u为根的子树中出现的a次的数的和与出现b次的数的和的gcd。

    2、询问u到v的树链中出现的a次的数的和与出现b次的数的和的gcd。

    有点绕。。

    分析:

    因为自己不会树上莫队,所以学习了一波。

    但是对于子树我还是有所经验,可以转成dfs序来做,之前有做过类似的题,比如这题

    然而对于树链有点懵逼,虽然我觉得也能用dfs序做,不过看大佬们的dfs序做的树链查询,也有点懵,感觉写起来很麻烦。

    貌似是修改了dfs序,回溯的时候不再只是和进入时相同的序,而是独立的序。

    还是感觉麻烦。。后来发现一个基于树分块的树上莫队,感觉很强。代码显然没有前者复杂。所以就用了它。

    第一种询问其实有nlogn的做法,跟上面的之前做过的 dfs序题是同一题。

    但是这里写的代码好长啊。。虽然很挫。。

    代码:

      1 #include <iostream>
      2 #include <cstdio>
      3 #include <algorithm>
      4 #include <cmath>
      5 #include <cstring>
      6 #include <set>
      7 #include <vector>
      8 #include <queue>
      9 #include <map>
     10 #include <list>
     11 #include <bitset>
     12 #include <string>
     13 #include <cctype>
     14 #include <cstdlib>
     15 
     16 using namespace std;
     17 
     18 typedef long long ll;
     19 typedef unsigned long long ull;
     20 #define inf (0x3f3f3f3f)
     21 #define lnf (0x3f3f3f3f3f3f3f3f)
     22 #define eps (1e-8)
     23 int sgn(double a) {
     24     return a < -eps ? -1 : a < eps ? 0 : 1;
     25 }
     26 
     27 const int maxn = 100010;
     28 
     29 int t;
     30 struct Q {
     31     int u, v, a, b;
     32     int l, r;
     33     int index;
     34 };
     35 
     36 
     37 int col[maxn];
     38 int cnt[maxn];
     39 ll cs[maxn];
     40 ll ans[maxn];
     41 const int bk = 316;
     42 
     43 const int DEG = 20;
     44 vector<Q> query[3];
     45 vector<int> g[maxn];
     46 
     47 int n, q;
     48 int a[maxn], b[maxn];
     49 
     50 inline bool scan_d(int &num) {
     51     char in;
     52     bool IsN = false;
     53     in = getchar();
     54     if(in == EOF) return false;
     55     while(in != '-' && (in < '0' || in > '9')) in = getchar();
     56     if(in == '-') {
     57         IsN = true;
     58         num = 0;
     59     } else num = in - '0';
     60     while(in = getchar(), in >= '0' && in <= '9') {
     61         num *= 10, num += in - '0';
     62     }
     63     if(IsN) num = -num;
     64     return true;
     65 }
     66 
     67 void initHash() {
     68     for(int i = 1; i <= n; i++) {
     69         b[i] = a[i];
     70     }
     71     sort(b + 1, b + n + 1);
     72     int p = unique(b + 1, b + n + 1) - b - 1;
     73     for(int i = 1; i <= n; i++) {
     74         a[i] = lower_bound(b + 1, b + n + 1, a[i]) - b;
     75     }
     76 }
     77 
     78 int L[maxn];
     79 int R[maxn];
     80 int d[maxn];
     81 int tot = 0;
     82 
     83 void dfs(int u, int fa, int dep) {
     84     L[u] = ++tot;
     85     d[u] = dep;
     86     col[tot] = a[u];
     87     for (int i = 0; i < g[u].size(); i++) {
     88         int v = g[u][i];
     89         if (v == fa)continue;
     90         dfs(v, u, dep + 1);
     91     }
     92     R[u] = tot;
     93 }
     94 
     95 
     96 
     97 bool cmp(Q a, Q b) {
     98     if(a.l / bk == b.l / bk)return a.r < b.r;
     99     else return a.l / bk < b.l / bk;
    100 }
    101 
    102 
    103 /// find_block
    104 int block[maxn], bcnt, bsize;
    105 int stk[maxn], top;
    106 
    107 void add_block(int &cnt) {
    108     while(cnt--) block[stk[--top]] = bcnt;
    109     bcnt++;
    110     cnt = 0;
    111 }
    112 
    113 void rest_block() {
    114     while(top) block[stk[--top]] = bcnt - 1;
    115 }
    116 
    117 int dfs_block(int u, int f) {
    118     int s = 0;
    119     for(int i = 0; i < g[u].size(); i++) {
    120         int v = g[u][i];
    121         if(v == f) continue;
    122         s += dfs_block(v, u);
    123         if(s >= bsize) add_block(s);
    124     }
    125     stk[top++] = u;
    126     s++;
    127     if(s >= bsize) add_block(s);
    128     return s;
    129 }
    130 
    131 void init_block() {
    132     bsize = bk;
    133     dfs_block(1, 0);
    134     rest_block();
    135 }
    136 
    137 
    138 /// ask_rmq
    139 int fa[DEG][maxn];
    140 int dep[maxn];
    141 
    142 void dfs_lca(int u, int f, int depth) {
    143     dep[u] = depth;
    144     fa[0][u] = f;
    145     for(int i = 0; i < g[u].size(); i++) {
    146         int v = g[u][i];
    147         if(v != f) dfs_lca(v, u, depth + 1);
    148     }
    149 }
    150 
    151 void init_lca() {
    152     dfs_lca(1, -1, 0);
    153     for(int k = 0; k + 1 < DEG; ++k) {
    154         for(int u = 1; u <= n; ++u) {
    155             if(fa[k][u] == -1) fa[k + 1][u] = -1;
    156             else fa[k + 1][u] = fa[k][fa[k][u]];
    157         }
    158     }
    159 }
    160 
    161 int ask_lca(int u, int v) {
    162     if(dep[u] < dep[v]) swap(u, v);
    163     for(int k = 0; k < DEG; ++k) {
    164         if((dep[u] - dep[v]) & (1 << k)) u = fa[k][u];
    165     }
    166     if(u == v) return u;
    167     for(int k = DEG - 1; k >= 0; --k) {
    168         if(fa[k][u] != fa[k][v])
    169             u = fa[k][u], v = fa[k][v];
    170     }
    171     return fa[0][u];
    172 }
    173 /// modui
    174 bool vis[maxn];
    175 
    176 void xorNode(int u) {
    177     if(vis[u]) {
    178         vis[u] = false;
    179         cs[cnt[a[u]]] -= b[a[u]];
    180         cnt[a[u]]--;
    181         cs[cnt[a[u]]] += b[a[u]];
    182     } else {
    183         vis[u] = true;
    184         cs[cnt[a[u]]] -= b[a[u]];
    185         cnt[a[u]]++;
    186         cs[cnt[a[u]]] += b[a[u]];
    187     }
    188 }
    189 
    190 void xorPathWithoutLca(int u, int v) {
    191     if(dep[u] < dep[v]) swap(u, v);
    192     while(dep[u] != dep[v])
    193         xorNode(u), u = fa[0][u];
    194     while(u != v)
    195         xorNode(u), u = fa[0][u], xorNode(v), v = fa[0][v];
    196 }
    197 
    198 void moveNode(int u, int v, int taru, int tarv) {
    199     xorPathWithoutLca(u, taru);
    200     xorPathWithoutLca(v, tarv);
    201     //printf("debug %d %d
    ", ask_lca(u, v), ask_lca(taru, tarv));
    202     xorNode(ask_lca(u, v));
    203     xorNode(ask_lca(taru, tarv));
    204 }
    205 
    206 
    207 bool cmp2(Q a, Q b) {
    208     if(block[a.u] == block[b.u])return block[a.v] < block[b.v];
    209     else return block[a.u] < block[b.u];
    210 }
    211 
    212 
    213 void solve() {
    214     scan_d(t);
    215     int c = 0;
    216     while(t--) {
    217         tot = 0;
    218         memset(cs, 0, sizeof(cs));
    219         memset(cnt, 0, sizeof(cnt));
    220         memset(vis, 0, sizeof(vis));
    221         for(int i = 1; i <= n; i++) {
    222             g[i].clear();
    223         }
    224         query[1].clear();
    225         query[2].clear();
    226         scan_d(n);
    227         scan_d(q);
    228         for(int i = 1; i <= n; i++) {
    229             scan_d(a[i]);
    230         }
    231         initHash();
    232         for(int i = 0; i < n - 1; i++) {
    233             int u, v;
    234             scan_d(u);
    235             scan_d(v);
    236             g[u].push_back(v);
    237             g[v].push_back(u);
    238         }
    239         dfs(1, -1, 1);
    240         init_block();
    241         init_lca();
    242         for(int i = 0; i < q; i++) {
    243             int op, u, v, a, b;
    244             scan_d(op);
    245             scan_d(u);
    246             scan_d(v);
    247             scan_d(a);
    248             scan_d(b);
    249             query[op].push_back(Q{u, v, a, b, L[u], R[u], i});
    250         }
    251         sort(query[1].begin(), query[1].end(), cmp);
    252 
    253 
    254         int pl = 1, pr = 0;
    255 
    256         for (int i = 0; i < query[1].size(); i++) {
    257             int index = query[1][i].index;
    258             if (pr < query[1][i].r) {
    259                 for (int j = pr + 1; j <= query[1][i].r; j++) {
    260                     cs[cnt[col[j]]] -= b[col[j]];
    261                     cnt[col[j]]++;
    262                     cs[cnt[col[j]]] += b[col[j]];
    263                 }
    264             } else {
    265                 for (int j = pr; j > query[1][i].r; j--) {
    266                     cs[cnt[col[j]]] -= b[col[j]];
    267                     cnt[col[j]]--;
    268                     cs[cnt[col[j]]] += b[col[j]];
    269                 }
    270             }
    271             pr = query[1][i].r;
    272             if (pl < query[1][i].l) {
    273                 for (int j = pl; j < query[1][i].l; j++) {
    274                     cs[cnt[col[j]]] -= b[col[j]];
    275                     cnt[col[j]]--;
    276                     cs[cnt[col[j]]] += b[col[j]];
    277                 }
    278             } else {
    279                 for (int j = pl - 1; j >= query[1][i].l; j--) {
    280                     cs[cnt[col[j]]] -= b[col[j]];
    281                     cnt[col[j]]++;
    282                     cs[cnt[col[j]]] += b[col[j]];
    283                 }
    284             }
    285             pl = query[1][i].l;
    286             ans[index] = __gcd(cs[query[1][i].a], cs[query[1][i].b]);
    287         }
    288         memset(cs, 0, sizeof(cs));
    289         memset(cnt, 0, sizeof(cnt));
    290 
    291 
    292         for(int i = 0; i < query[2].size(); i++) {
    293             if(block[query[2][i].u] > block[query[2][i].v]) swap(query[2][i].u, query[2][i].v);
    294         }
    295         sort(query[2].begin(), query[2].end(), cmp2);
    296 
    297         int nowu = 1, nowv = 1;
    298         xorNode(1);
    299         for(int i = 0; i < query[2].size(); i++) {
    300             int index = query[2][i].index;
    301             moveNode(nowu, nowv, query[2][i].u, query[2][i].v);
    302             ans[index] = __gcd(cs[query[2][i].a], cs[query[2][i].b]);
    303             nowu = query[2][i].u, nowv = query[2][i].v;
    304         }
    305         printf("Case #%d:
    ", ++c);
    306         for(int i = 0; i < q; i++) {
    307             printf("%lld
    ", ans[i]);
    308         }
    309 
    310     }
    311 
    312 }
    313 
    314 
    315 
    316 int main() {
    317 
    318 #ifndef ONLINE_JUDGE
    319     freopen("1.in", "r", stdin);
    320     //freopen("1.out", "w", stdout);
    321 #endif
    322     //iostream::sync_with_stdio(false);
    323     solve();
    324     return 0;
    325 }
  • 相关阅读:
    从POJ1958引发对n盘m塔Hanoi问题的思考
    SPOJGSS3 Can you answer these queries III
    【模板】SPFA判负环(洛谷P3385)
    【模板】强联通缩点(洛谷P3387)
    Luogu P2186 小Z的栈函数
    Luogu P2129 小Z的情书
    LGBT学分块
    LGBT玩扫雷
    A 美丽的子树
    B(升降序列)
  • 原文地址:https://www.cnblogs.com/tak-fate/p/7143749.html
Copyright © 2020-2023  润新知