• 4538: [Hnoi2016]网络 链剖 + 堆(优先队列) / 整体二分


    GDOI之后写的第一道题。看到之后没什么感觉(是我太弱,中途一度想用kpm之前在某道题上用过的链表的方法。想了想应该不可能。)

    好!让我们来分析这道题吧!首先简化模型,它是要求维护树上的一些路径,支持添加和修改,要求不经过某个点的路径的最大权值(不经过某个点,我一度想到了动点分,虽然我还不会)。

    我们可以先考虑在链上(其实仔细一想,如果链上的你会做,那么树上的大多数情况下便是多个了链剖而已吧!)的情况。在链上,有一些区间覆盖,要求没有覆盖某个点的区间的最大权值。那么我们接着想如果询问2询问了一个点,那么所有覆盖了这个点的区间都是无效的。换句话说如果A这个区间内含有N个点,那么A这个区间对于这N个点是无效,而对于其他的所有点都是有效的。所以接下来,如果是链上的,一个区间的有效范围便是 1—— 左端点-1, 右端点+1——N。  再把它搬回树上,接下来链剖之后,x -- y 的路径可能有 log2N个区间, 要一个个修改。再乘上线段树的log2N。 复杂度大概是log2N的平方*m。 (另外因为维护最大值所以线段树上的节点都是堆,当然C++的肯定就用优先队列了。)

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<queue>
     4 #include<algorithm>
     5 #define rep(i,j,k) for(register int i = j; i <= k; i++)
     6 #define ez(i,j) for(edge*i = head[j]; i; i=i->next)
     7 #define maxn 100233
     8 using namespace std;
     9 
    10 struct edge{ int to; edge*next; } e[maxn*2], *pt = e, *head[maxn];
    11 inline void add(int x,int y) { pt->to = x, pt->next = head[y], head[y] = pt++; pt->to = y, pt->next = head[x], head[x] = pt++; }
    12 
    13 int fa[maxn], dep[maxn], top[maxn], w[maxn], son[maxn], sz[maxn], tot = 0;
    14 #define to i->to
    15 inline void dfs1(int x) {
    16     sz[x] = 1; son[x] = 0;
    17     ez(i,x) {
    18         if( to == fa[x] ) continue;
    19         fa[to] = x; dep[to] = dep[x] + 1; dfs1(to); 
    20         sz[x] += sz[to]; if( sz[to] > sz[son[x]] ) son[x] = to; 
    21     } 
    22 } 
    23 inline void dfs2(int x,int ph) {
    24     top[x] = ph; w[x] = ++tot;
    25     if( son[x] ) dfs2(son[x],ph);
    26     ez(i,x) if( to != son[x] && to != fa[x] ) dfs2(to,to);
    27 }
    28 
    29 inline int read() {
    30     int s = 0, t = 1; char c = getchar();
    31     while( !isdigit(c) ) { if( c == '-' ) t = -1; c = getchar(); }
    32     while( isdigit(c) ) s = s * 10 + c - 48, c = getchar();
    33     return s * t;
    34 }
    35 struct node{ int l, r; bool operator < (const node&rhs) const { return l < rhs.l; } } nod[maxn];
    36 priority_queue<int> a[maxn*4], b[maxn*4];
    37 inline int attop(int x) {
    38     while( !a[x].empty() && !b[x].empty() ) {
    39         if( a[x].top() == b[x].top() )  a[x].pop(), b[x].pop(); 
    40         else break; 
    41     }
    42     if( a[x].empty() ) return -1;
    43     else return a[x].top();
    44 }
    45 int ql, qr, n, m, d;
    46 #define mid ((l+r)>>1)
    47 inline void add(int l,int r,int k,int flag) {
    48     if( ql > qr ) return;
    49     if( ql <= l && r <= qr ) { if( flag ) a[k].push(d); else b[k].push(d); return; }
    50     if( ql <= mid ) add(l,mid,k<<1,flag); if( qr > mid ) add(mid+1,r,k<<1|1,flag); 
    51 }
    52 
    53 inline void update(int x,int y,int flag) {
    54     int tot = 0;
    55     while( top[x] != top[y] ) {
    56         if( dep[top[x]] < dep[top[y]] ) swap(x,y);
    57         nod[++tot].l = w[top[x]], nod[tot].r = w[x];
    58         x = fa[top[x]];
    59     }
    60     if( dep[x] > dep[y] ) swap(x,y);
    61     nod[++tot].l = w[x], nod[tot].r = w[y];
    62     sort(nod+1,nod+tot+1);
    63     int nowl = 1;
    64     rep(i,1,tot) {
    65         ql = nowl, qr = nod[i].l - 1;
    66         add(1,n,1,flag);
    67         nowl = nod[i].r + 1;
    68     }
    69     ql = nowl, qr = n;
    70     add(1,n,1,flag);
    71 }
    72 inline int query(int l,int r,int k) {
    73     if( l == r ) return attop(k);
    74     if( ql <= mid ) return max(attop(k),query(l,mid,k<<1));
    75     else return max(attop(k),query(mid+1,r,k<<1|1));
    76 }
    77 
    78 int q1[maxn<<1], q2[maxn<<1], q3[maxn<<1];
    79 
    80 int main() {
    81     n = read(), m = read(); int flag, x, y;
    82     rep(i,1,n-1) add(read(),read());
    83     dfs1(1); dfs2(1,1); 
    84     rep(i,1,m) {
    85         flag = read();
    86         if( !flag ) q1[i] = read(), q2[i] = read(), d = q3[i] = read(), update(q1[i],q2[i],1);
    87         else if( flag == 1 ) x = read(), d = q3[x], update(q1[x],q2[x],0);
    88         else ql = qr = w[read()], printf("%d
    ", query(1,n,1));
    89     }
    90     return 0;
    91 }

    整体二分

    简单讲一下cdq分治和整体二分的区别吧!(基于我的理解)。 cdq分治通常使用在一些有多个约束条件的场合,为了去掉一些约束条件,而使用。总的来说还是用数据结构维护一些数据,只是用了这种思想后可以大大简化问题(例如把二维的题变成一维之类的),在NlongN时间内解答。而整体二分是二分答案,把问题从一个求值的题,转变成为判定性问题,通过一些途径,判断答案是否能达到某个值。因此整体二分一般应该是用来求最值(或第k大)一类的(我的理解)。

    在这里,如果一条路径经过了某个点。 那么它的一个终点(或者两个)必定在以该点为根的子树内。那我们想一下如果两个终点都在以该点为根的子树内,那么该点必定是这两个终点的lca。

    而如果两个终点都在以该点为根的子树,而不经过该点,那么该点必定是这两个终点的lca的祖先。因此就可以维护经过某个点的路径有多少。

    二分答案K,维护权值大于答案K的路径。假设当前权值大于答案K的路径有num条,而当前经过某个点的路径恰为num条,那么对于这个询问答案必定小于K

     1 #include<cstdio>
     2 #include<iostream>
     3 #define rep(i,j,k) for(register int i = j; i <= k; i++)
     4 #define dow(i,j,k) for(register int i = j; i >= k; i--)
     5 #define ez(i,j) for(edge*i = head[j]; i; i=i->next)
     6 #define maxn 102333
     7 using namespace std;
     8 
     9 struct edge{ int to; edge*next; } e[maxn<<1], *pt = e, *head[maxn];
    10 inline void add(int x,int y) { pt->to = y, pt->next = head[x], head[x] = pt++; pt->to = x, pt->next = head[y], head[y] = pt++; }
    11 
    12 inline int read() {
    13     int s = 0, t = 1; char c = getchar();
    14     while( !isdigit(c) ) { if( c == '-' ) t = -1; c = getchar(); }
    15     while( isdigit(c) ) s = s * 10 + c - 48, c = getchar();
    16     return s * t;
    17 }
    18 
    19 int tot = 0, n, m, dep[maxn], bin[17], fa[maxn][17], t[maxn] = {0}, ti[maxn] = {0}, now = 0, L[maxn], R[maxn];
    20 #define lower(x) (x & -x)
    21 #define to i->to
    22 inline int query(int x) { int ret = 0; while( x ) { if( ti[x] == now ) ret += t[x]; x -= lower(x); } return ret; }
    23 inline void update(int x,int d) { while( x <= n ) if( ti[x] == now ) t[x] += d, x += lower(x); else ti[x] = now, t[x] = d, x += lower(x); } 
    24 inline void dfs(int x) {
    25     L[x] = ++tot;
    26     rep(i,1,16) if( dep[x] >= bin[i] ) fa[x][i] = fa[fa[x][i-1]][i-1];
    27     ez(i,x) if( to != fa[x][0] ) fa[to][0] = x, dep[to] = dep[x] + 1, dfs(to);
    28     R[x] = tot;
    29 }
    30 inline int lca(int x,int y) {
    31     if( dep[x] < dep[y] ) swap(x,y);
    32     if( dep[x] != dep[y] ) {
    33         int dis = dep[x] - dep[y];
    34         rep(i,0,16) if( dis & bin[i] ) dis -= bin[i], x = fa[x][i]; else if( !dis ) break;
    35     } 
    36     if( x == y ) return x;
    37     dow(i,16,0) if( fa[x][i] != fa[y][i] ) x = fa[x][i], y = fa[y][i];
    38     return fa[x][0];
    39 }
    40 
    41 struct node{ int x, y, flag, d; } nod[maxn<<1];
    42 int ans[maxn<<1], t1[maxn<<1], t2[maxn<<1], bel[maxn<<1];
    43 inline void solve(int l,int r,int al,int ar) {
    44     if( al == ar ) { rep(i,l,r) ans[bel[i]] = al; return; }
    45     int mid = (al + ar) >> 1;
    46     int l1 = 0, l2 = 0, num = 0, x, y, z, tot; now++;
    47     bool nedl = 0, nedr = 0;
    48     rep(i,l,r) 
    49             if( !nod[bel[i]].flag ) {
    50                 if( nod[bel[i]].d <= mid ) { t1[++l1] = bel[i]; continue; }
    51                 t2[++l2] = bel[i]; num++; x = nod[bel[i]].x, y = nod[bel[i]].y, z = lca(x,y); 
    52                 update(L[x],1); update(L[y],1); update(L[z],-1); if( fa[z][0] ) update(L[fa[z][0]],-1);
    53             } else if( nod[bel[i]].flag == 1 ) {
    54                 if( nod[bel[i]].d <= mid ) { t1[++l1] = bel[i]; continue; }
    55                 t2[++l2] = bel[i]; num--; x = nod[bel[i]].x, y = nod[bel[i]].y, z = lca(x,y);
    56                 update(L[x],-1); update(L[y],-1); update(L[z],1); if( fa[z][0] ) update(L[fa[z][0]],1); 
    57             } else {
    58                 x = nod[bel[i]].x;
    59                 tot = query(R[x]) - query(L[x]-1);
    60                 if( tot < num ) t2[++l2] = bel[i], nedr = 1;
    61                 else t1[++l1] = bel[i], nedl = 1;
    62             }
    63     rep(i,l,l+l1-1) bel[i] = t1[i-l+1];
    64     rep(i,l+l1,r) bel[i] = t2[i-l-l1+1];
    65     if( nedl ) solve(l,l+l1-1,al,mid);
    66     if( nedr ) solve(l+l1,r,mid+1,ar);
    67 }
    68 
    69 int main() {
    70     n = read(), m = read();
    71     bin[0] = 1; rep(i,1,16) bin[i] = bin[i-1] << 1;
    72     rep(i,1,n-1) add(read(),read()); dfs(1);
    73     int mx = 0, x;
    74     rep(i,1,m) {
    75         nod[i].flag = read();
    76         if( !nod[i].flag ) nod[i].x = read(), nod[i].y = read(), nod[i].d = read(), mx = max(nod[i].d,mx);
    77         else if( nod[i].flag == 1 ) x = read(), nod[i].x = nod[x].x, nod[i].y = nod[x].y, nod[i].d = nod[x].d; 
    78         else nod[i].x = read(); 
    79     }
    80     rep(i,1,m) bel[i] = i, ans[i] = -1;
    81     solve(1,m,-1,mx);
    82     rep(i,1,m) if( nod[i].flag == 2 ) printf("%d
    ", ans[i]);
    83     return 0;
    84 }
    RunID User Problem Result Memory Time Language Code_Length Submit_Time
    1433099 CCTVhq 4538 Accepted 19924 kb 8952 ms C++/Edit 3562 B 2016-05-04 19:52:05
    1432903 CCTVhq 4538 Accepted 47080 kb 6628 ms C++/Edit 3001 B 2016-05-04 18:30:31

    上面那个是整体二分的。

    下面是链剖的。

  • 相关阅读:
    PowerTalk第一个版本儿控件
    PowerTalk第二个版本,支持(Msn回复信息)
    自然语言处理著作或期刊名称
    自然语言处理(NLP)网上资源整理 (转)
    TFIDF
    计算机科学及工程
    自然语言处理与计算语言学书籍汇总之一:国外书籍
    UVa 10696 f91
    缓存
    操作必须使用一个可更新的查询(转)
  • 原文地址:https://www.cnblogs.com/83131yyl/p/5459614.html
Copyright © 2020-2023  润新知