bzoj3995

线段树

额 计蒜客竟然把这个出成noip模拟题。。。

这个东西很像1018,只不过维护的东西不太一样

然后我参考了fuxey大神的代码,盗一波图

具体有这五种情况,合并请看代码,自己写了一个结果wa了,然后就copy了一下。。。

然后build的时候不用把叶子结点的值赋成inf,感觉奥妙重重

#include<bits/stdc++.h>
using namespace std;
const int N = 60010;
int n, m;
int tree[N << 3][5], a[N], b[N], c[N], ans[5];
void up(int &a, const int &b) { a = min(a, b); } /*
void maintain(int a[5], int l[5], int r[5], int mn, int sm)
{
    memset(a, 0x3f3f3f3f, sizeof(tree[0]));
    up(a[0], l[0] + r[0] + mn);
    up(a[0], l[0] + r[3] + sm);
    up(a[0], l[3] + r[0] + sm);
    up(a[0], l[1] + r[0] + sm);
    up(a[0], l[0] + r[2] + sm);
    up(a[1], l[0] + r[1] + mn);
    up(a[1], l[3] + r[1] + sm);
    up(a[1], l[0] + r[4] + sm);
    up(a[1], l[0] + r[3] + mn);
    up(a[1], l[0] + r[4] + mn);
    up(a[1], l[0] + r[2] + mn);
    up(a[2], l[2] + r[0] + mn);
    up(a[2], l[4] + r[0] + sm);
    up(a[2], l[3] + a[0] + mn);
    up(a[2], l[1] + r[0] + mn);
    up(a[2], l[2] + r[3] + sm);
    up(a[2], l[2] + r[2] + sm);
    up(a[3], l[3] + r[3] + sm);
    up(a[4], l[2] + r[1] + mn);
    up(a[4], l[2] + r[3] + mn);
    up(a[4], l[2] + r[4] + sm);
    up(a[4], l[3] + r[1] + mn);
    up(a[4], l[3] + r[4] + sm);
    up(a[4], l[2] + r[1] + mn);
    up(a[4], l[4] + r[3] + sm);
    up(a[4], l[4] + r[1] + sm);
    up(a[4], l[3] + r[3] + mn);
} */
void maintain(int a[5] , int l[5] , int r[5] , int mn , int sm)
{
    memset(a , 0x3f3f , sizeof(tree[0]));

    up(a[0] , l[0] + r[0] + mn);
    up(a[1] , l[0] + r[1] + mn);
    up(a[0] , l[0] + r[2] + sm);
    up(a[0] , l[0] + r[3] + sm);
    up(a[1] , l[0] + r[3] + mn);
    up(a[1] , l[0] + r[4] + sm);

    up(a[0] , l[1] + r[0] + sm);
    up(a[1] , l[1] + r[1] + sm);
    up(a[1] , l[1] + r[3] + sm);

    up(a[2] , l[2] + r[0] + mn);
    up(a[4] , l[2] + r[1] + mn);
    up(a[2] , l[2] + r[2] + sm);
    up(a[2] , l[2] + r[3] + sm);
    up(a[4] , l[2] + r[3] + mn);
    up(a[4] , l[2] + r[4] + sm);    

    up(a[0] , l[3] + r[0] + sm);
    up(a[1] , l[3] + r[1] + sm);
    up(a[4] , l[3] + r[1] + mn);
    up(a[3] , l[3] + r[3] + sm);
    up(a[4] , l[3] + r[3] + mn);
    up(a[4] , l[3] + r[4] + sm);

    up(a[2] , l[4] + r[0] + sm);
    up(a[4] , l[4] + r[1] + sm);
    up(a[4] , l[4] + r[3] + sm);
}

void build(int l, int r, int o)
{
    if(l == r)
    {
        tree[o][0] = c[l];
//      tree[o][1] = tree[o][2] = 0x3f3f3f3f;
        return;
    }
    int mid = (l + r) >> 1;
    build(l, mid, o << 1);
    build(mid + 1, r, o << 1 | 1);
    int mn = min(a[mid], b[mid]), sm = a[mid] + b[mid];
    maintain(tree[o], tree[o << 1], tree[o << 1 | 1], mn, sm);
//  printf("l = %d r = %d\n", l, r);
//  for(int i = 0; i < 5; ++i) printf("tree[%d][%d] = %d\n", o, i, tree[o][i]);
}
void update(int l, int r, int o, int pos)
{
    if(l == r)
    {
        tree[o][0] = c[l];
        return;
    }
    int mid = (l + r) >> 1;
    if(pos <= mid) update(l, mid, o << 1, pos);
    else update(mid + 1, r, o << 1 | 1, pos);
    int mn = min(a[mid], b[mid]), sm = a[mid] + b[mid];
    maintain(tree[o], tree[o << 1], tree[o << 1 | 1], mn, sm);
}
bool query(int l, int r, int o, int la, int lb, int tmp[5])
{
    if(l > lb || r < la) return false;
    if(l >= la && r <= lb)
    {
        for(int i = 0; i < 5; ++i) tmp[i] = tree[o][i];
        return true;
    }
    int mid = (l + r) >> 1, tmp1[5], tmp2[5];
    bool flag1 = query(l, mid, o << 1, la, lb, tmp1);
    bool flag2 = query(mid + 1, r, o << 1 | 1, la, lb, tmp2);
    if(flag1 && flag2)
    {
        int mn = min(a[mid], b[mid]), sm = a[mid] + b[mid];
        maintain(tmp, tmp1, tmp2, mn, sm);
        return true;
    }
    if(flag1)
    {
        for(int i = 0; i < 5; ++i) tmp[i] = tmp1[i];
        return true;
    }
    if(flag2)
    {
        for(int i = 0; i < 5; ++i) tmp[i] = tmp2[i];
        return true;
    }
    return false;
}
int main()
{
    cin >> n >> m;
    for(int i = 1; i < n; ++i) scanf("%d", &a[i]);
    for(int i = 1; i < n; ++i) scanf("%d", &b[i]);
    for(int i = 1; i <= n; ++i) scanf("%d", &c[i]);
    build(1, n, 1);
    while(m--)
    {
        int x0, x1, y0, y1, w;
        char opt[10];
        scanf("%s", opt);
        if(opt[0] == ‘C‘)
        {
            scanf("%d%d%d%d%d", &x0, &y0, &x1, &y1, &w);
            if(x0 == x1)
            {
                if(y0 > y1) swap(y0, y1);
                if(x0 == 1) a[y0] = w;
                if(x0 == 2) b[y0] = w;
                update(1, n, 1, y0);
                update(1, n, 1, y1);
            }
            if(y0 == y1)
            {
                c[y0] = w;
                update(1, n, 1, y0);
            }
        }
        if(opt[0] == ‘Q‘)
        {
            scanf("%d%d", &y0, &y1);
            query(1, n, 1, y0, y1, ans);
            printf("%d\n", ans[0]);
        }
    }
    return 0;
}

时间: 2024-10-22 20:40:06

bzoj3995的相关文章

【线段树】bzoj3995 [SDOI2015]道路修建

线段树每个结点维护5个域: 整个区间的MST. 将两个左端点连通,两个右端点不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块. 将两个右端点连通,两个左端点不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块. 两个左端点不连通,两个右端点也不连通,整个区间内选择2*(r-l+1)-2条边的最小生成森林,有两个连通块.(就是上面一条线,下面一条线) 两个左端点不连通,两个右端点也不连通,整个区间内选择2*(r-l+1)-3条边的最小生成森林,有

bzoj3995[SDOI2015]道路修建

http://www.lydsy.com/JudgeOnline/problem.php?id=3995 线段树维护连通性. 我们发现,对于一个区间[L,R],我们只需要知道(1,L),(2,L),(1,R)和(2,R)这4个点的之间的连通情况即可. 我们在线段树中,假设当前节点的表示的区间的为[L,R],我们需要知道(1,L),(2,L),(1,R)和(2,R)这4个点的之间的连通情况,但是为了方便,我们记了(1,L),(2,L),(1,R+1)和(2,R+1)这4个点的连通情况. 每个节点记