zoukankan      html  css  js  c++  java
  • bzoj2286:[SDOI2011]消耗战

    传送门

    虚树裸题,建完虚树上tree dp就好了
    代码:

    #include<cstdio>
    #include<iostream>
    #include<algorithm>
    #include<cstring>
    using namespace std;
    void read(int &x) {
        char ch; bool ok;
        for(ok=0,ch=getchar(); !isdigit(ch); ch=getchar()) if(ch=='-') ok=1;
        for(x=0; isdigit(ch); x=x*10+ch-'0',ch=getchar()); if(ok) x=-x;
    }
    #define rg register
    const int maxn=2.5e5+10;
    int f[maxn][20],nid,dep[maxn],top,st[maxn],n,m,id[maxn],q[maxn];
    struct oo{int cnt,pre[maxn*2],nxt[maxn*2],h[maxn],v[maxn*2];}a,b;
    long long w[maxn],ans[maxn];
    void add(int x,int y,int z)
    {
        a.pre[++a.cnt]=y,a.nxt[a.cnt]=a.h[x],a.h[x]=a.cnt,a.v[a.cnt]=z;
        a.pre[++a.cnt]=x,a.nxt[a.cnt]=a.h[y],a.h[y]=a.cnt,a.v[a.cnt]=z;
    }
    void dfs(int x,int fa)
    {
        for(rg int i=1;i<20;i++)
        {
            if((1<<i)>dep[x])break;
            f[x][i]=f[f[x][i-1]][i-1];
        }
        id[x]=++nid;
        for(rg int i=a.h[x];i;i=a.nxt[i])
            if(a.pre[i]!=fa)
            {
                f[a.pre[i]][0]=x,dep[a.pre[i]]=dep[x]+1;
                w[a.pre[i]]=min(w[x],1ll*a.v[i]),dfs(a.pre[i],x);
            }
    }
    int lca(int x,int y)
    {
        if(dep[x]>dep[y])swap(x,y);
        int poor=dep[y]-dep[x];
        for(rg int i=19;i>=0;i--)if(poor&(1<<i))y=f[y][i];
        for(rg int i=19;i>=0;i--)if(f[x][i]!=f[y][i])x=f[x][i],y=f[y][i];
        return x==y?x:f[x][0];
    }
    bool cmp(int x,int y){return id[x]<id[y];}
    void link(int x,int y)
    {
        b.pre[++b.cnt]=y,b.nxt[b.cnt]=b.h[x],b.h[x]=b.cnt;
        b.pre[++b.cnt]=x,b.nxt[b.cnt]=b.h[y],b.h[y]=b.cnt;
    }
    void dp(int x,int fa)
    {
        long long now=0;ans[x]=w[x];
        for(rg int i=b.h[x];i;i=b.nxt[i])if(b.pre[i]!=fa)dp(b.pre[i],x),now+=ans[b.pre[i]];
        b.h[x]=0;
        if(now)ans[x]=min(ans[x],now);
    //	printf("%d %d %d
    ",x,ans[x],w[x]);
    }
    signed main()
    {
        read(n);
        for(rg int i=1,x,y,z;i<n;i++)read(x),read(y),read(z),add(x,y,z);
        w[1]=1e17,dfs(1,0),read(m);
        for(rg int x=1,t;x<=m;x++)
        {
            read(t),b.cnt=top=0;
            for(rg int i=1;i<=t;i++)read(q[i]);
            sort(q+1,q+t+1,cmp);st[++top]=1;int tot=1;
            for(rg int i=2;i<=t;i++)if(lca(q[i],q[tot])!=q[tot])q[++tot]=q[i];
            for(rg int i=1;i<=tot;i++)
            {
                int w=0,e=0;
                while(top&&lca(st[top],q[i])!=st[top])
                {
                    if(w)link(w,st[top]);
                    w=st[top],top--;
                }
                if(w)e=lca(w,q[i]),link(w,e);
                if(e&&e!=st[top])st[++top]=e;
                st[++top]=q[i];
            }
            while(top>1)link(st[top],st[top-1]),top--;
            dp(1,0);
            printf("%lld
    ",ans[1]);
        }
    }
    
  • 相关阅读:
    linux源码阅读笔记 asm函数
    linux源码阅读笔记 #define 语句的妙用
    对于python的内存管理的好文章
    #define x do{......} while(0)的用处
    reverse list
    判断数组是否存在重复元素
    找出数组中出现奇数次的元素
    找出数组中唯一的重复元素
    两个有序数组中的交集
    Java Socket(3): NIO
  • 原文地址:https://www.cnblogs.com/lcxer/p/10369454.html
Copyright © 2011-2022 走看看