多校第一场1006

来源:互联网 发布:vscode 大小写快捷键 编辑:程序博客网 时间:2024/06/05 04:58

题目描述:

给出一棵树,n~1e5,然后给出m~1e5条特殊的链,每个链有一个权值.现在在树上挑选不相交的链,使得最后的拿到的权值最大.

题解:

看一个点,是树形dp,但是发现如果u是root,枚举过u的链,发现要暴力求和链上周围的点的dp和.这样会超时. 于是想到快速求一条链的和. 为了好写,我们把求链上连接的儿子的dp值的和转化到链上的权值. sum[u]指u的所有儿子的dp和,这个好想,那么一条链上的其实就是(sum[u] - 所有链上儿子d+链上儿子的sum-链上儿子儿子的d….),总结就是链上除了root,其他的点权值都是sum[v]-d[v].而root的权值是sum[root]. 我们是算d[u]的时候才用的,当时d[u]肯定就是0. 所以求链上的权值和. 我们有两种求法
(1)邓爷教的标序+lca. 这样求的是路径,我们用一种常用的方法,把i的值归到i到他fa的那条边上. 这样我们求路径+sum[root]就行了.
(2)用树链剖分. 映射到树状数组上,每次求和.

重点:

(1)关键是求一条链上的和.
(2)把权值归到链上,简化写法.
(3)点的权值归到u到fa的边上.
(4)标序或者树链剖分求链的和
(5)标序+st表求lca

代码:

//这个是标序算链的和.#pragma comment(linker, "/STACK:1024000000,1024000000")#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(int i = a;i < b;i++)#define REP_D(i, a, b) for(int i = a;i <= b;i++)typedef long long ll;using namespace std;const int maxn = 1e5 + 100;const int maxRMQ = 4e5 + 100;const int maxIND = 2e5 + 1000;const int maxTree = 1e6 + 100;int nn, m;struct Edge{    int a, b, val;};vector<Edge> edge[maxn];vector<int> G[maxn];int st[maxRMQ][50], L2[maxRMQ], P2[50];int dfn, index[maxn], fa_index[maxn], first_u[maxn];int a_st[maxRMQ], an;int dfx, getin[maxn], getout[maxn];int d[maxn], sum[maxn];//void pushUp(int rt)//{//    int lRt = (rt<<1), rRt = ((rt<<1)|1);//    tree[rt] = tree[lRt]+tree[rRt];//}//void change(int pos, int key, int rt, int l, int r)//{//    if(l==r && l == pos)//主义同时修改tree//    {//        tree[rt] = key;//        return;//    }//    pushDown(rt);//    int mid = ((l + r)>>1), lRt = (rt<<1), rRt = ((rt<<1)|1);//    if(pos <= mid)//    {//        change(pos,key, lRt, l, mid);//    }//    if(pos >= mid + 1)//    {//        change(pos, key, rRt, mid + 1, r);//    }//    pushUp(rt);//向上push//}////int query(int L, int R, int rt, int l, int r)//{//    if(L <= l && R >= r)//全包括//    {//        return tree[rt];//    }//    int ans =0, mid = ((l + r)>>1), lRt = (rt<<1), rRt = ((rt<<1)|1);//    if(L <= mid)//    {//        ans += query(L, R, lRt, l, mid);//    }//    if(R >= mid + 1)//    {//        ans += query(L, R, rRt, mid + 1, r);//    }//    return ans;//}void dfs_dfn(int u, int fa)//这是lca{    dfn++;    index[u] = dfn;    fa_index[dfn] = u;    an++;    a_st[an] = dfn;    first_u[u] = an;    REP(i, 0, G[u].size())    {        int v = G[u][i];        if(v!=fa)        {            dfs_dfn(v, u);            an++;            a_st[an] = index[u];        }    }}void getL2(){    L2[1] = 0;    for(int i = 2; i<=400000; i++)    {        if((i&(i-1))==0)        {            L2[i] = L2[i-1]+1;        }        else        {            L2[i] = L2[i-1];        }        //printf("%d %d\n", i, L2[i]);    }}void initail(){    P2[0] = 1;    for(int i = 1; i<=30; i++)    {        P2[i] = 2*P2[i-1];    }    for(int i = 1; i <= an; i++)    {        st[i][0] = a_st[i];        //printf(" i is %d  %d\n", i, a_st[i]);    }    for(int s = 1; s<=30; s++)    {        for(int i = 1; i+P2[s] - 1 <=an; i++)        {            int j = i+P2[s-1];            st[i][s] = min(st[i][s-1], st[j][s-1]);        }    }}int st_query(int a, int b){    int len = (b-a+1);    int s = L2[len];    return min(st[a][s], st[b-P2[s]+1][s]);}int getLca(int a, int b)//lca结束{    int l = first_u[a], r = first_u[b];    if(l > r)    {        swap(l, r);    }    return fa_index[st_query(l, r)];}int tree[maxn << 1];//树状数组int getsum(int x){    int ret = 0;    while (x)    {        ret += tree[x];        x -= (x & (-x));    }    return ret;}void update(int x, int y){    while (x <= dfx)    {        tree[x] += y;        x += (x & (-x));    }}void dfs_xu(int u, int fa){    dfx++;    getin[u] = dfx;    REP(i, 0, G[u].size())    {        int v = G[u][i];        if(v!=fa)        {            dfs_xu(v, u);        }    }    dfx++;    getout[u] = dfx;}int getT(int a, int b){    if(a==1)    {        return getsum(b);    }    return getsum(b)-getsum(a-1);}int getSum_t(int a, int b, int lca){    int l = getin[lca];    int r = getin[a];    int ans = 0;    ans += getT(l, r);    r = getin[b];    ans += getT(l, r);    return ans;}void dfs(int u, int fa)//树形dp,求和链上.{    sum[u] = 0;    REP(i, 0, G[u].size())    {        int v = G[u][i];        if(v!=fa)        {            dfs(v, u);            sum[u] += d[v];        }    }    d[u] = sum[u];    REP(i, 0, edge[u].size())    {        Edge e = edge[u][i];        int a = e.a, b = e.b, val = e.val;//        if(u == 2)//        {//            for(int i = 1; i<=dfx; i++)//            {//                printf("tree i is %d  %d\n", i, tree[i]);//            }//        }        int tmp = getSum_t(a, b, u);        d[u] = max(d[u], tmp + sum[u] + val);    }    //printf("%d  %d %d\n", u, sum[u], d[u]);    update(getin[u], sum[u]-d[u]);    update(getout[u], d[u]-sum[u]);    //change(getin[u], sum[u]-d[u], 1, 1, dfx);    //change(getout[u], d[u]-sum[u], 1, 1, dfx);}void solve(){    REP_D(i, 1, nn)    {        G[i].clear();        edge[i].clear();    }    REP_D(i, 1, nn - 1)    {        int a, b;        scanf("%d%d", &a, &b);        G[a].push_back(b);        G[b].push_back(a);    }    dfn = 0;    an = 0;    dfs_dfn(1, 0);    initail();    REP_D(i, 1, m)    {        int a, b, val;        scanf("%d%d%d", &a, &b, &val);        int lca = getLca(a, b);        Edge t;        t.a = a;        t.b = b;        t.val = val;        edge[lca].push_back(t);        //printf("lca %d %d %d\n", a, b, lca);    }    CLR(tree);    CLR(sum);    CLR(d);    dfx = 0;    dfs_xu(1,0);    dfs(1, 0);    printf("%d\n", d[1]);}int main(){   // freopen("13Min.txt", "r", stdin);    //freopen("1out.txt", "w", stdout);    int t;    getL2();    scanf("%d", &t);    while(t--)    {        scanf("%d%d", &nn,&m);        solve();    }    return 0;}//这个是树链剖分,但是线段树要re....所以没有过#pragma comment(linker, "/STACK:1024000000,1024000000")#include <iostream>#include <cstdio>#include <cstring>#include <string>#include <cmath>#include <ctype.h>#include <limits.h>#include <cstdlib>#include <algorithm>#include <vector>#include <queue>#include <map>#include <stack>#include <set>#include <bitset>#define CLR(a) memset(a, 0, sizeof(a))#define REP(i, a, b) for(int i = a;i < b;i++)#define REP_D(i, a, b) for(int i = a;i <= b;i++)typedef long long ll;using namespace std;const int maxn = 1e5 + 100;const int maxLMQ = 4*maxn+100;const int MAXL = 30;int st[maxLMQ][MAXL];int an, a[maxLMQ];int index[maxn], fa_index[maxn], first_byindex[maxn];int dfn;vector<int> G[maxn];struct Edge{    int a, b, val, lca;};Edge edge[maxn];vector<Edge> lca_edge[maxn];int edge_n;int P2[maxn], L2[maxn];int d[maxn], sum[maxn];int dep[maxn], w[maxn], fa[maxn], top[maxn], son[maxn], siz[maxn];int z;int tree[maxLMQ];int n;void getP2(){    P2[0] = 1;    for(int i = 1; i<=30; i++)    {        P2[i] = P2[i-1]*2;    }}void getL2(){    L2[1] = 0;    for(int i = 2; i<=400000; i++)    {        if((i&(i-1))==0)        {            L2[i] = L2[i-1]+1;        }        else        {            L2[i] = L2[i-1];        }        //printf("%d %d\n", i, L2[i]);    }}void initail(){    for(int i = 1; i <= an; i++)    {        st[i][0] = a[i];    }    for(int s = 1; s<=30; s++)    {        for(int i = 1; i<= an; i++)        {            int j = i+P2[s-1];            if(j>=an)                continue;            st[i][s]= min(st[i][s-1],st[j][s-1]);        }    }}int query(int l, int r){    int len = (r-l+1);    int s = L2[len];    int tmp = P2[s];    return min(st[l][s], st[r - tmp + 1][s]);}int getLca(int a, int b){    a = index[a];    b = index[b];    int l = first_byindex[a], r = first_byindex[b];    if(l > r)    {        swap(l, r);    }    return fa_index[query(l, r)];}void dfs_dfn(int u, int fa){    ++an;    a[an] = dfn;    first_byindex[dfn] = an;    index[u] = dfn;    fa_index[dfn] = u;    dfn++;    REP(i, 0, G[u].size())    {        int v = G[u][i];        if(v!=fa)        {            dfs_dfn(v, u);            an++;            a[an] = index[u];        }    }}void getEdge(){    REP_D(i, 1, n)    {        lca_edge[i].clear();    }    REP(i, 0, edge_n)    {        scanf("%d%d%d", &edge[i].a, &edge[i].b, &edge[i].val);        edge[i].lca = getLca(edge[i].a, edge[i].b);        lca_edge[edge[i].lca].push_back(edge[i]);    }}void dfs_1(int u, int pat)//先准备{    siz[u] = 1;    son[u] = 0;    REP(i, 0, G[u].size())    {        int v = G[u][i];        if(v!=pat)        {            fa[v] = u;            dep[v] = dep[u]+1;            dfs_1(v, u);            if(son[u]==0)            {                son[u] = v;            }            else if(siz[v] > siz[son[u]])            {                son[u] = v;            }            siz[u] += siz[v];        }    }}void dfs_2(int u, int pat, int tp)//标号边{    if(pat != 0)    {        z++;        w[u] = z;    }    top[u] = tp;    if(son[u] !=0)    {        dfs_2(son[u], u, top[u]);    }    REP(i, 0, G[u].size())    {        int v = G[u][i];        if(v!=pat&&v!=son[u])        {            dfs_2(v, u, v);        }    }}int query_tree(int LL, int RR, int rt, int l, int r){    if(LL<=l && RR>= r)    {        return tree[rt];    }    int ans = 0;    int mid = ((l + r)>>1), lRt = (rt<<1), rRt = ((rt<<1)|1);    if(LL<=mid)    {        ans += query_tree(LL, RR, lRt, l, mid);    }    if(RR>=mid+1)    {        ans += query_tree(LL, RR, rRt, mid+1, r);    }    return ans;}void pushUp(int rt){    int lRt = (rt<<1), rRt = ((rt<<1)|1);    tree[rt] = tree[lRt]+ tree[rRt];}void update(int pos, int x, int rt, int l, int r){    if(pos == l && pos == r)    {        tree[rt] = x;        return;    }    int mid = ((l + r)>>1), lRt = (rt<<1), rRt = ((rt<<1)|1);    if(pos <= mid)    {        update(pos, x, lRt, l, mid);    }    else    {        update(pos , x, rRt, mid +1, r);    }    pushUp(rt);}int getSum(int a, int b){    int f1 = top[a], f2 = top[b];    int ans = 0;    while(f1 != f2)    {        if(dep[f1] < dep[f2])        {            swap(f1, f2);            swap(a, b);        }        ans += (query_tree(w[f1], w[a], 1, 1, z));        a = fa[f1];        f1 = top[a];    }    if(a==b)        return ans;    if(dep[a] > dep[b])    {        swap(a, b);    }    ans += query_tree(w[son[a]], w[b], 1, 1, z);    return ans;}void dfs(int u, int pat){    sum[u]= 0;    REP(i, 0, G[u].size())    {        int v = G[u][i];        if(v!=pat)        {            dfs(v, u);            sum[u] += d[v];        }    }    d[u] = sum[u];    REP(i, 0, lca_edge[u].size())    {        Edge &e = lca_edge[u][i];        int a = e.a, b = e.b, val = e.val;        int temp = getSum(e.a, e.b);        d[u]=max(d[u], temp+sum[u]+val);    }    if(u!=1)    {        update(w[u], sum[u]-d[u], 1, 1, z);    }    //printf("%d %d  %d \n", u, sum[u], d[u]);}void solve(){    CLR(tree);    dfn = 1;    an = 0;    dfs_dfn(1, 0);    initail();    getEdge();    dep[1] = 0;    dfs_1(1, 0);    z = 0;    dfs_2(1, 0, 1);    dfs(1, 0);    printf("%d\n", d[1]);}int main(){    //freopen("6Fin.txt", "r", stdin);    //freopen("6Fout.txt", "w", stdout);    getP2();    getL2();    int t;    scanf("%d", &t);    while(t--)    {        scanf("%d%d", &n, &edge_n);        REP_D(i, 1, n)        {            G[i].clear();        }        REP_D(i, 1, n-1)        {            int a, b;            scanf("%d%d", &a, &b);            G[a].push_back(b);            G[b].push_back(a);        }        solve();    }    return 0;}
0 0
原创粉丝点击