[2015hdu多校联赛补题]hdu5296 Annoying problem

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5296

题意:给你一棵n个结点的边权树和一个树上点的集合,开始时集合为空

然后进行两种操作:

1、如果结点u不在集合中,那么将u加入集合

2、如果结点u在集合中,那么删除u

每次操作后输出包含点集合的最小联通子图的边权和

题解:

其实问题的本质就是求结点u与子图的距离(如果在子图内部距离为0),yy一下可以想到,若x、y为集合中与u最近的两点,那么dis(u,子图)=dis(u,联通u、x、y三点的汇点)

问题转化为求x、y,将树上结点以dfs序重标号,如果u在点集标号集的外侧,那么x、y分别为点集标号集的最大标号与最小标号,如果在内侧,那么x、y分别为u的左右

然后求u与 联通u、x、y三点汇点 的距离:

dis(u,联通u、x、y三点的汇点)=(dis(u,x)+dis(u,y)+dis(x,y))/2-dis(x,y)

dis(a,b)=dfn[a] +dfn[b] -2dfn[lca(a,b)] (lca和dfn都是求树链长度用到的东西,lca(a,b):a、b的最近公共祖先,dfn[x]:根结点到x的路径的边权和)

  1 /*
  2  * Problem:
  3  * Author:  SHJWUDP
  4  * Created Time:  2015/8/2 星期日 15:20:01
  5  * File Name: 233.cpp
  6  * State:
  7  * Memo:
  8  */
  9 #include <iostream>
 10 #include <cstdio>
 11 #include <cstring>
 12 #include <algorithm>
 13 #include <vector>
 14 #include <set>
 15
 16 using namespace std;
 17
 18 struct Edge {
 19     int u, v, w;
 20     Edge(int u, int v, int w):u(u), v(v), w(w){}
 21 };
 22
 23 int n, q;
 24 vector<Edge> edges;
 25 vector<vector<int> > G;
 26 vector<int> pos, id, dep, dfn;
 27 vector<vector<int> > fa;
 28 set<int> S;
 29 int root, cnt;
 30 void init(int sz) {
 31     edges.clear();
 32     G.assign(sz, vector<int>(0));
 33     S.clear();
 34     pos.resize(sz);
 35     id.resize(sz);
 36     dep.resize(sz);
 37     dfn.resize(sz);
 38     fa.assign(sz, vector<int>(20));
 39 }
 40 void addEdge(int u, int v, int w) {
 41     edges.push_back(Edge(u, v, w));
 42     G[u].push_back(edges.size()-1);
 43 }
 44 void dfs(int u) {
 45     pos[u]=++cnt;
 46     id[cnt]=u;
 47     for(int k=1; k<20; k++) {
 48         fa[u][k]=fa[fa[u][k-1]][k-1];
 49     }
 50     for(int i : G[u]) {
 51         Edge & e=edges[i];
 52         if(e.v==fa[u][0]) continue;
 53         dfn[e.v]=dfn[u]+e.w;
 54         dep[e.v]=dep[u]+1;
 55         fa[e.v][0]=u;
 56         dfs(e.v);
 57     }
 58 }
 59 int lca(int u, int v) {
 60     if(dep[u]<dep[v]) swap(u, v);
 61     for(int k=19; k>=0; k--) {
 62         if(dep[fa[u][k]]>=dep[v]) {
 63             u=fa[u][k];
 64         }
 65     }
 66     if(u==v) return u;
 67     for(int k=19; k>=0; k--) {
 68         if(fa[u][k]!=fa[v][k]) {
 69             u=fa[u][k]; v=fa[v][k];
 70         }
 71     }
 72     return fa[u][0];
 73 }
 74 int func(int u) {
 75     int res=0;
 76     if(!S.empty()) {
 77         auto it=S.lower_bound(pos[u]);
 78         int x, y;
 79         if(it==S.begin() || it==S.end()) {
 80             x=id[*S.begin()];
 81             y=id[*S.rbegin()];
 82         } else {
 83             x=id[*it];
 84             y=id[*--it];
 85         }
 86         res=dfn[u]-dfn[lca(u, x)]-dfn[lca(u, y)]+dfn[lca(x, y)];
 87     }
 88     return res;
 89 }
 90 int main() {
 91 #ifndef ONLINE_JUDGE
 92     freopen("in", "r", stdin);
 93     //freopen("out", "w", stdout);
 94 #endif
 95     int T, now=0;
 96     scanf("%d", &T);
 97     while(T--) {
 98         scanf("%d%d", &n, &q);
 99         init(n+1);
100         for(int i=0; i<n-1; i++) {
101             int a, b, c;
102             scanf("%d%d%d", &a, &b, &c);
103             addEdge(a, b, c);
104             addEdge(b, a, c);
105         }
106         root=1; cnt=0; fa[root][0]=root; dep[root]=0; dfn[root]=0; dfs(root);
107         printf("Case #%d:\n", ++now);
108         int ans=0;
109         while(q--) {
110             int op, u;
111             scanf("%d%d", &op, &u);
112             auto it=S.find(pos[u]);
113             if(op==1 && it==S.end()) {
114                 ans+=func(u);
115                 S.insert(pos[u]);
116             } else if(op==2 && it!=S.end()) {
117                 S.erase(it);
118                 ans-=func(u);
119             }
120             printf("%d\n", ans);
121         }
122     }
123     return 0;
124 }

hdu 5296

时间: 2024-08-10 21:28:54

[2015hdu多校联赛补题]hdu5296 Annoying problem的相关文章

[2015hdu多校联赛补题]hdu5371 Hotaru&#39;s problem

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5371 题意:把一个数字串A翻过来(abc翻过来为cba)的操作为-A,我们称A-AA这样的串为N-sequence,现在给你一个数字串,问你这个串中最长的N-sequence子串长度 解:可以想到A-A是一个回文串,-AA也是一个回文串,那么首先Manacher跑一遍求出所有回文子串 可以想到任意两个互相覆盖的回文子串都可以表示成N-sequence 然后有三种搞法: 1.时间复杂度O(N*logN

[2015hdu多校联赛补题]hdu5348 MZL&#39;s endless loop

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5348 题意:给你一个无向图,要你将无向图的边变成有向边,使得得到的图,出度和入度差的绝对值小于等于1,如果无解输出-1 解:考虑奇数度的点一定会成对出现(因为所有度数和肯定是偶数个->因为一条边产生两度~),那么我们可以将奇数度的点两两一连消除掉(两奇数度点的出度入读差的绝对值都为1, 路径上的点的差绝对值为0) 然后偶数度的点可以成环,那么可以搜出所有的环 1 /* 2 * Problem: 3

[2015hdu多校联赛补题]hdu5302 Connect the Graph

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5302 题意:给你一个无向图,它的边要么是黑色要么是白色,且图上的每个点最多与两个黑边两个白边相连.现在,Demon将图分成两部分,一部分包含所有的黑边,另一部分包括所有的白边,给你白边图中度为0的点的数量w0,度为1的点数w1,度为2的点数w2,与黑边图中度为0的点数b1,度为1的点数b1,度为2的点数b2,要你输出任意一个符合条件的原图,如果不能,输出-1 (注1:无论是黑边图,还是白边图,给出的

[2015hdu多校联赛补题]hdu5384 Danganronpa

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5384 题意:函数f(A, B)定义:A.B为字符串,f(A, B)为A中有多少个不同的B(ex:f("ababa", "aba")==2   f("ababa", "bab")==1),现在给你一组A串,一组B串,问你对每个A串的是多少 解:ac自动机模板题,可以把A串用'z'+1,连成一个串处理起来比较方便 1 /* 2 * P

[2015hdu多校联赛补题]hdu5378 Leader in Tree Land

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5378 题意:给你一棵n个结点的有根树.因为是有根树,那么每个结点可以指定以它为根的子树(后面讨论的子树都是这个).现在我们把标号从1到n的n个minister派驻到这些结点上面(每个结点派驻一人),并规定任一子树中编号最大的minister 为该子树的领导,问你存在多少个不同的领导 解: 引用官方题解: 可以用求概率的思想来解决这个问题.令以i号节点为根的子树为第i棵子树,设这颗子树恰好有sz[i]

[2015hdu多校联赛补题]hdu5372 Segment Game

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5372 题意:进行n次操作,操作分两种,0和1,每一个0操作按出现顺序有一个编号(从1开始 0操作 0 x:询问[x, x+i](i为该操作的编号)区间内有多少个完整的线段,并加入线段[x, x+i](线段直接重叠不影响) 1操作 1 x:删除0操作中插入的编号为x的线段,(不影响其他线段,不会重复删除同一线段,删除的线段一定是已经插入的) 解:题目有一个重要的条件:后面插入的线段一定比前面的长.那么

[2015hdu多校联赛补题]hdu5301 Buildings

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5301 题目大意:给你一块由1x1方格组成的矩形区域,其中有且仅有一个坏块,现在你要在上面建矩形的房子, 要求: 1.除坏块以外任何一个1x1方格上都要有房子覆盖 2.任何一座房子都必须有一部分作为矩形区域的边界 3.要使所建房子中面积最大的面积尽量小 要你输出这个所建房子中面积最大的那个房子的面积 解: 大概想一下,面积最大的房子肯定是1*x的长条,因为对任何y来说1*x的长条都可以拼成y*x的长条

[2015hdu多校联赛补题]hdu5324 Boring Class

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5324 题意:给你一个二维的序列,让你找出最长的第一维升第二维降的子序列(如果多个答案,输出字典序最小) 解:考虑从后往前dp,在u点你需要知道u点之后的比u的第一维大,第二维小的dp最大值 可以用分治枚举u点之后比u的第一维大的点,然后用树状数组查询比u的第二维小的点中dp最大的 1 /* 2 * Problem: 3 * Author: SHJWUDP 4 * Created Time: 2015

[2015hdu多校联赛补题]hdu 5297 Y sequence

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=5297 题意:给你一个所有正整数的序列,然后去掉满足x^(2~r)的所有数(x为所有正整数,r>=2题目给出),问你现在这个序列的第n个数是什么 解:首先想到写一个函数func(y),它可以计算出给定数字y是序列中第几个数,这样我们大概可以二分答案~(事实上会TLE,得用迭代法,当然迭代的话也是用这个函数) 那么如何实现func: 首先想去掉满足x^2的所有数,我们可以用pow(y, 1/2)计算出y