您的位置:首页 > 大数据 > 人工智能

hdu 5296 - Annoying problem(2015 Multi-University Training Contest 1 )LCA

2015-07-27 21:47 351 查看
Annoying problem

Time Limit: 16000/8000 MS (Java/Others) Memory Limit: 65536/65536 K (Java/Others)

Total Submission(s): 865 Accepted Submission(s): 286

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<=1000000) 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=1or2,1<=y<=nx=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

又是一个神题,题解是这样说的:




这也是非常神奇的,对于一个点,找他的dfs须,离他最近的两个,正好把他夹住,如果夹不住,那么找字典序最大最小的两个,然后把它加到这两个点的链上,花费就是图中的公式

[code]#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<vector>
#include<cmath>
#include<queue>
#include<stack>
#include<map>
#include<set>
#include<algorithm>
using namespace std;
typedef long long LL;
const int maxn=100010;
const int maxm=100010;
const int INF=0x3f3f3f3f;
int N,Q;
int dep[maxn],fa[maxn],anc[maxn][20];
int num[maxn],dfn[maxn];
int head[maxn],tot,len[maxn],id[maxn];
int dfs_clock;
set<int> sp;
struct node
{
    int v,next,w;
}edge[maxn*2];
void init()
{
    tot=dfs_clock=0;
    memset(head,-1,sizeof(head));
    memset(len,0,sizeof(len));
}
void dfs(int u,int f,int depth,int sum)
{
    dep[u]=depth;
    dfn[u]=++dfs_clock;
    id[dfs_clock]=u;
    fa[u]=f;
    num[u]=1;
    len[u]=sum;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==f)continue;
        dfs(v,u,depth+1,sum+edge[i].w);
        num[u]+=num[v];
        fa[v]=u;
    }
}
void preprocess()
{
    for(int i=1;i<=N;i++)
    {
        anc[i][0]=fa[i];
        for(int j=1;(1<<j)<=N;j++)
            anc[i][j]=-1;
    }
    for(int j=1;(1<<j)<=N;j++)
    {
        for(int i=1;i<=N;i++)
        {
            if(anc[i][j-1]==-1)continue;
            int a=anc[i][j-1];
            anc[i][j]=anc[a][j-1];
        }
    }
}
int LCA(int p,int q)
{
    if(dep[p]<dep[q])swap(p,q);
    int k=0;
    while((1<<(k+1))<=dep[p])k++;
    for(int i=k;i>=0;i--)
        if(dep[p]-(1<<i)>=dep[q])p=anc[p][i];
    if(p==q)return p;
    for(int i=k;i>=0;i--)
        if(anc[p][i]!=-1&&anc[p][i]!=anc[q][i])
            p=anc[p][i],q=anc[q][i];
    return fa[p];
}
void add_edge(int u,int v,int w)
{
    edge[tot].v=v;
    edge[tot].next=head[u];
    edge[tot].w=w;
    head[u]=tot++;
}
int solve(int u)
{
    if(sp.empty())return 0;
    set<int>::iterator it=sp.lower_bound(u);
    int x=*sp.begin();
    int y=*sp.rbegin();
    if(y>=u&&x<=u)
    {
        x=id[*it];
        it--;
        y=id[*it];
    }
    else x=id[x],y=id[y];
    u=id[u];
    return len[u]-len[LCA(x,u)]-len[LCA(u,y)]+len[LCA(x,y)];
}
int main()
{
    int T,cas=1;
    int x,y,z,op;
    scanf("%d",&T);
    while(T--)
    {
        init();
        scanf("%d%d",&N,&Q);
        for(int i=1;i<N;i++)
        {
            scanf("%d%d%d",&x,&y,&z);
            add_edge(x,y,z);
            add_edge(y,x,z);
        }
        dfs(1,-1,0,0);
        preprocess();
        sp.clear();
        int ans=0;
        printf("Case #%d:\n",cas++);
        while(Q--)
        {
            scanf("%d%d",&op,&x);
            x=dfn[x];
            if(op==1)
            {
                if(sp.find(x)==sp.end())
                {
                    ans+=solve(x);
                    sp.insert(x);
                }
            }
            else
            {
                if(sp.find(x)!=sp.end())
                {
                    sp.erase(x);
                    ans-=solve(x);
                }
            }
            printf("%d\n",ans);
        }
    }
    return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: