HDU 5296 Annoying problem


Annoying problem

Time Limit: 16000/8000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others)
Total Submission(s): 203    Accepted Submission(s): 60


Problem Description
Coco has a tree, whose nodes are conveniently labeled by 1,2,…,n, which has n-1 edge,each edge has a weight. An existing set S is initially empty.
Now there are two kinds of operation:

1 x: If the node x is not in the set S, add node x to the set S
2 x: If the node x is in the set S,delete node x from the set S

Now there is a annoying problem: In order to select a set of edges from tree after each operation which makes any two nodes in set S connected. What is the minimum of the sum of the selected edges’ weight ?

 

Input
one integer number T is described in the first line represents the group number of testcases.( T<=10 ) 
For each test:
The first line has 2 integer number n,q(0<n,q<=100000) describe the number of nodes and the number of operations.
The following n-1 lines each line has 3 integer number u,v,w describe that between node u and node v has an edge weight w.(1<=u,v<=n,1<=w<=100)
The following q lines each line has 2 integer number x,y describe one operation.(x=1 or 2,1<=y<=n)


 

Output
Each testcase outputs a line of "Case #x:" , x starts from 1.
The next q line represents the answer to each operation.

 

Sample Input
  
  
1 6 5 1 2 2 1 5 2 5 6 2 2 4 2 2 3 2 1 5 1 3 1 4 1 2 2 5
 

Sample Output
  
  
Case #1: 0 6 8 8 4
 

Author
FZUACM
 

Source
 


#include <bits/stdc++.h>
using namespace std;
#define prt(k) cerr<<#k" = "<<k<<endl
typedef unsigned long long ll;

const int N = 233333;
int n, m, head[N], mm;
struct Edge
{
    int to, next, w;
} e[N << 1];
void add(int u, int v, int w = 1)
{
    e[mm].to = v;
    e[mm].next = head[u];
    e[mm].w = w;
    head[u] = mm++;
}
int sz[N], dep[N];
int f[N][22]; /// f[i][j] 表示 i 的第 2^j 个祖先
int dfn[N];  ///dfs index
int cur;
int id[N]; /// you dfs xu qiu chu bian hao
int len[N];
void dfs(int u, int fa) /// 点从 1 开始标号
{
    f[u][0] = fa;
    sz[u] = 1;
    dfn[u] = ++cur;
    id[cur] = u;
    for (int i=head[u]; ~i; i=e[i].next)
    {
        int v = e[i].to;
        int w = e[i].w;
        if (v != fa)
        {
            dep[v] = dep[u] + 1;
            len[v] = len[u] + w;
            dfs(v, u);
            sz[u] += sz[v];
        }
    }
}
int maxh;
void gao()
{
    cur = 0;
    dep[0] = -1;
    len[1] = dep[1] = 0;
    f[1][0] = 1;
    dfs(1, 0);f[1][0] = 1;
    int j;
    for (j=1; (1<<j)<n; j++)
        for (int i=1; i<=n; i++)
            f[i][j] = f[f[i][j-1]][j-1];
    maxh = j - 1;
}
int swim(int x, int k)
{
    for (int i=0; i<=maxh; i++)
        if (k >> i & 1)
            x = f[x][i];
    return x;
}
int LCA(int x, int y)
{
    if (dep[x] > dep[y]) swap(x, y); ///dep[x] <= dep[y];
    y = swim(y, dep[y] - dep[x]);
    if (x == y) return y;
    for (int i=maxh; i>=0; i--)
    {
        if (f[x][i] != f[y][i])
            x = f[x][i], y = f[y][i];
    }
    return f[x][0];
}
int Q;

set<int> se;
set<int>::iterator it;
int dist(int x, int y)
{
    int lca = LCA(x, y);
    return len[x] - len[lca] + len[y] - len[lca];
}
int solve(int u)
{
    if (se.empty()) return 0;
    int x, y;
    int t = *se.begin();
    it = se.lower_bound( u);
    y = *it;
    it--;
    x = *(it );
    int t2 = *se.rbegin();
    x = id[x];
    y = id[y];
    if (t2 < u || t > u)
    {
        x = id[t]; y = id[t2];
    }
    u = id[u];
    return len[u] - len[LCA(x,u) ] - len[LCA(y,u)] + len[LCA(x,y) ];
}
int main()
{
    int re;
    cin>>re;
    int ca=1;
    while (re--)
    {
        cin>>n>>Q;
        mm = 0;
        memset(head,-1,sizeof head);
        for (int i=0; i<n-1; i++)
        {
            int u, v, w;
            scanf("%d%d%d", &u, &v, &w);
            add(u, v, w);
            add(v, u, w);
        }
        gao();
        printf("Case #%d:\n", ca++);
        se.clear();
        int ans = 0;
        while (Q--)
        {
            int op, u;
            scanf("%d%d", &op, &u);
            u = dfn[u];
            if (op==1)
            {
                it = se.find(u);
                if (it==se.end())
                {
                    ans += solve(u);
                    se.insert(u);
                }
            }
            else
            {
                it = se.find(u);
                if (it != se.end())
                {
                    se.erase(u);
                    ans -= solve(u);
                }
            }
            printf("%d\n", ans);
        }
    }
    return 0;
}


  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值