zoukankan      html  css  js  c++  java
  • 洛谷P5163 WD与地图

    只有洛谷的毒瘤才会在毒瘤月赛里出毒瘤题......

    题意:三个操作,删边,改变点权,求点x所在强连通分量内前k大点权之和。

    解:狗屎毒瘤数据结构乱堆......

    整体二分套(tarjan+并查集) + 线段树合并。

    首先可以变成加边。

    然后就是神奇操作让人难以置信......

    对于每条边,我们有个时刻t使得它的两端点在同一scc内。那么如何求出这个t呢?

    整体二分!...这又是怎么想到的啊......

    对于一个时刻mid,我们把小于它的边提取出来缩点,如果有的边两端点在一个scc,那么它的t就不大于mid。否则大于mid。

    为了保证整体二分的复杂度,我们每次操作tarjan的图不能太大。具体来说,把之前做过的区间的scc用并查集缩起来。

    对于每条边,提取两端点所在scc的代表元为关键点,构出虚图(?????),然后tarjan。

    之后递归左边,之后并查集缩点,之后递归右边。

    所有t求出之后,再倒着跑一遍询问,按照时刻把边的两端点在并查集中合并(表示成为一个scc),并对权值线段树进行合并。

    查询就是所在scc的权值线段树的前k大之和,这个好办。

    注意爆int。我写了300行7k......

      1 #include <cstdio>
      2 #include <algorithm>
      3 #include <vector>
      4 #include <cstring>
      5 #include <stack>
      6 #include <map>
      7 
      8 typedef long long LL;
      9 const int N = 100010, M = 400010, V = 40000010;
     10 
     11 struct Edge {
     12     int nex, v;
     13 }edge[M]; int tp;
     14 
     15 struct Node {
     16     int t, x, y, id;
     17 }node[M], t1[M], t2[M];
     18 
     19 struct Ask {
     20     int f, x, y;
     21     LL ans;
     22 }ask[M];
     23 
     24 std::vector<Node> v[M];
     25 std::stack<int> S;
     26 std::map<int, int> mp[N];
     27 int e[N], fr[N], stk[N], top, dfn[N], low[N], use[N], X[N + M], xx, rt[N], sum[V], ls[V], rs[V], val[N];
     28 int Time, scc_cnt, num, n, m, q, tot;
     29 LL Val[V];
     30 
     31 inline void add(int x, int y) {
     32     tp++;
     33     edge[tp].v = y;
     34     edge[tp].nex = e[x];
     35     e[x] = tp;
     36     return;
     37 }
     38 
     39 namespace ufs {
     40     int fa[N];
     41     int find(int x) {
     42         if(fa[x] == x) {
     43             return x;
     44         }
     45         return fa[x] = find(fa[x]);
     46     }
     47     inline void merge(int x, int y) {
     48         fa[find(x)] = find(y);
     49         return;
     50     }
     51     inline void clear() {
     52         for(int i = 1; i <= n; i++) {
     53             fa[i] = i;
     54         }
     55         return;
     56     }
     57 }
     58 
     59 void tarjan(int x) {
     60     low[x] = dfn[x] = ++num;
     61     S.push(x);
     62     //printf("tarjan %d 
    ", x);
     63     for(int i = e[x]; i; i = edge[i].nex) {
     64         int y = edge[i].v;
     65         if(!dfn[y]) {
     66             tarjan(y);
     67             low[x] = std::min(low[x], low[y]);
     68         }
     69         else if(!fr[y]) { // find
     70             low[x] = std::min(low[x], dfn[y]);
     71         }
     72     }
     73     if(low[x] == dfn[x]) {
     74         //printf("getscc 
    ");
     75         ++scc_cnt;
     76         int y;
     77         do {
     78             y = S.top();
     79             //printf("%d ", y);
     80             S.pop();
     81             fr[y] = scc_cnt;
     82             //ufs::merge(x, y);
     83         } while(y != x);
     84         //puts("");
     85     }
     86     return;
     87 }
     88 
     89 inline void TAR() {
     90     scc_cnt = num = 0;
     91     for(int i = 1; i <= top; i++) {
     92         if(!dfn[stk[i]]) {
     93             tarjan(stk[i]);
     94         }
     95     }
     96     return;
     97 }
     98 
     99 inline void link(int x, int y) {
    100     x = ufs::find(x); y = ufs::find(y);
    101     if(use[x] != Time) {
    102         use[x] = Time;
    103         dfn[x] = fr[x] = e[x] = 0;
    104         stk[++top] = x;
    105     }
    106     if(use[y] != Time) {
    107         use[y] = Time;
    108         dfn[y] = fr[y] = e[y] = 0;
    109         stk[++top] = y;
    110     }
    111     add(x, y); // self-circle is OK
    112     return;
    113 }
    114 
    115 inline void solve(int L, int R, int l, int r) {
    116     if(R < L) {
    117         return;
    118     }
    119     //printf("solve %d %d %d %d 
    ", L, R, l, r);
    120     if(l == r) {
    121         for(int i = L; i <= R; i++) {
    122             v[r].push_back(node[i]);
    123         }
    124         return;
    125     }
    126     int mid = (l + r) >> 1;
    127     ++Time; top = tp = 0;
    128     for(int i = L; i <= R; i++) {
    129         if(node[i].t <= mid) {
    130             link(node[i].x, node[i].y);
    131         }
    132     }
    133     //int ufs_t = ufs::top;
    134     TAR();
    135     int top1 = 0, top2 = 0;
    136     for(int i = L; i <= R; i++) {
    137         int x = ufs::find(node[i].x), y = ufs::find(node[i].y);
    138         if(node[i].t <= mid && fr[x] == fr[y]) {
    139             t1[++top1] = node[i];
    140         }
    141         else {
    142             t2[++top2] = node[i];
    143         }
    144     }
    145     memcpy(node + L, t1 + 1, top1 * sizeof(Node));
    146     memcpy(node + L + top1, t2 + 1, top2 * sizeof(Node));
    147     solve(L, L + top1 - 1, l, mid);
    148     for(int i = L; i < L + top1; i++) {
    149         int x = ufs::find(node[i].x);
    150         int y = ufs::find(node[i].y);
    151         ufs::merge(x, y);
    152     }
    153     solve(L + top1, R, mid + 1, r);
    154     return;
    155 }
    156 
    157 int merge(int x, int y) {
    158     if(!x || !y || x == y) {
    159         return x | y;
    160     }
    161     int o = ++tot;
    162     sum[o] = sum[x] + sum[y];
    163     Val[o] = Val[x] + Val[y];
    164     ls[o] = merge(ls[x], ls[y]);
    165     rs[o] = merge(rs[x], rs[y]);
    166     return o;
    167 }
    168 
    169 void add(int p, int v, int l, int r, int &o) {
    170     //printf("add : %d %d  %d %d 
    ", p, v, l, r);
    171     if(!o) {
    172         o = ++tot;
    173     }
    174     if(l == r) {
    175         sum[o] += v;
    176         Val[o] += v * X[r];
    177         return;
    178     }
    179     int mid = (l + r) >> 1;
    180     if(p <= mid) {
    181         add(p, v, l, mid, ls[o]);
    182     }
    183     else {
    184         add(p, v, mid + 1, r, rs[o]);
    185     }
    186     sum[o] = sum[ls[o]] + sum[rs[o]];
    187     Val[o] = Val[ls[o]] + Val[rs[o]];
    188     return;
    189 }
    190 
    191 LL query(int k, int l, int r, int o) {
    192     //printf("query %d [%d %d] 
    ", k, l, r);
    193     if(!o) {
    194         return 0;
    195     }
    196     if(l == r) {
    197         return 1ll * std::min(k, sum[o]) * X[r];
    198     }
    199     int mid = (l + r) >> 1;
    200     if(sum[rs[o]] >= k) {
    201         return query(k, mid + 1, r, rs[o]);
    202     }
    203     else {
    204         return Val[rs[o]] + query(k - sum[rs[o]], l, mid, ls[o]);
    205     }
    206 }
    207 
    208 int main() {
    209 
    210     scanf("%d%d%d", &n, &m, &q);
    211     ufs::clear();
    212     for(int i = 1; i <= n; i++) {
    213         scanf("%d", &val[i]);
    214         X[++xx] = val[i];
    215     }
    216     for(int i = 1; i <= m; i++) {
    217         scanf("%d%d", &node[i].x, &node[i].y);
    218         mp[node[i].x][node[i].y] = i;
    219         node[i].id = i;
    220     }
    221     for(int i = 1; i <= q; i++) {
    222         scanf("%d%d%d", &ask[i].f, &ask[i].x, &ask[i].y);
    223         if(ask[i].f == 2) {
    224             ask[i].y += val[ask[i].x];
    225             X[++xx] = ask[i].y;
    226             std::swap(val[ask[i].x], ask[i].y);
    227         }
    228     }
    229     std::sort(X + 1, X + xx + 1);
    230     xx = std::unique(X + 1, X + xx + 1) - X - 1;
    231     for(int i = 1; i <= n; i++) {
    232         val[i] = std::lower_bound(X + 1, X + xx + 1, val[i]) - X;
    233     }
    234     for(int i = 1; i <= q; i++) {
    235         if(ask[i].f == 2) {
    236             ask[i].y = std::lower_bound(X + 1, X + xx + 1, ask[i].y) - X;
    237         }
    238     }
    239     std::reverse(ask + 1, ask + q + 1);
    240     for(int i = 1; i <= q; i++) {
    241         if(ask[i].f == 1) {
    242             int t = mp[ask[i].x][ask[i].y];
    243             node[t].t = i;
    244         }
    245     }
    246 
    247     solve(1, m, 1, q + 1);
    248     //printf("--------------------------------
    ");
    249     ufs::clear();
    250     for(int i = 1; i <= n; i++) {
    251         add(val[i], 1, 1, xx, rt[i]);
    252     }
    253     for(int i = 1; i <= q; i++) {
    254         //printf("i = %d 
    ", i);
    255         for(int j = 0; j < v[i].size(); j++) {
    256             //printf(" > edge = %d %d 
    ", v[i][j].x, v[i][j].y);
    257             int x = ufs::find(v[i][j].x), y = ufs::find(v[i][j].y);
    258             ufs::merge(x, y);
    259             int t = ufs::find(x);
    260             rt[t] = merge(rt[x], rt[y]);
    261             //printf("%d = merge %d %d 
    ", t, x, y);
    262         }
    263         if(ask[i].f == 3) {
    264             int t = ufs::find(ask[i].x);
    265             ask[i].ans = query(ask[i].y, 1, xx, rt[t]);
    266         }
    267         else if(ask[i].f == 2) {
    268             int t = ufs::find(ask[i].x);
    269             //printf("change %d : %d -> %d 
    ", ask[i].x, X[val[ask[i].x]], X[ask[i].y]);
    270             add(val[ask[i].x], -1, 1, xx, rt[t]);
    271             add(ask[i].y, 1, 1, xx, rt[t]);
    272             val[ask[i].x] = ask[i].y;
    273         }
    274     }
    275     for(int i = q; i >= 1; i--) {
    276         if(ask[i].f == 3) {
    277             printf("%lld
    ", ask[i].ans);
    278         }
    279     }
    280     return 0;
    281 }
    AC代码

    对拍真是个好东西。

  • 相关阅读:
    第八届蓝桥杯JavaC组国(决)赛真题
    第八届蓝桥杯JavaC组国(决)赛真题
    第八届蓝桥杯JavaC组国(决)赛真题
    第八届蓝桥杯JavaC组国(决)赛真题
    第八届蓝桥杯JavaC组国(决)赛真题
    Java实现蓝桥杯历届试题填字母游戏
    Java实现蓝桥杯历届试题填字母游戏
    Java实现蓝桥杯历届试题填字母游戏
    Java实现蓝桥杯历届试题填字母游戏
    Qt调用dll中的功能函数
  • 原文地址:https://www.cnblogs.com/huyufeifei/p/10403339.html
Copyright © 2011-2022 走看看