洛谷T44252 线索_分治线段树_思维题

分治线段树,其实就是将标记永久化,到最后再统一下传所有标记。
至于先后顺序,可以给每个节点开一个时间戳。
一般地,分治线段树用于离线,只查询一次答案的题目。
本题中,标记要被下传 2 2 2 次。
Code:

#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
const int maxn = 100000 + 10;
int n,m,  tag[maxn << 2], lazy[maxn << 2], siz[maxn], root[maxn], p[maxn], tag_root[maxn], ans[maxn];
int find(int x){ return p[x] == x ? x : p[x] = find(p[x]);  }
struct Segment_Tree
{
    # define lson (o << 1)
    # define rson (o << 1)|1 
    void update(int l, int r, int L, int R, int col, int times, int o)    
    {
        if(l > r || r < L || l > R) return ;
        if(l >= L && r <= R)
        {
            lazy[o] = col, tag[o] = times;
            return;
        }
        int mid = (l + r) >> 1;
        update(l, mid, L, R,col, times, lson);
        update(mid + 1, r, L, R, col , times, rson);
    }
    inline void pushdown(int o)
    {
        if(tag[o] > tag[lson]) 
            lazy[lson] = lazy[o], tag[lson] = tag[o];   
        if(tag[o] > tag[rson]) 
            lazy[rson] = lazy[o], tag[rson] = tag[o];
    }
    void release(int o, int l, int r)
    {
        if(l > r) return ;
        if(l == r)
        {
            int x = find(l);
            if(tag_root[x] > tag[o])
                ans[l] = root[x];
            else 
                ans[l] = lazy[o], tag_root[x] = tag[o], root[x] = lazy[o];
            return ;
        }
        int mid = (l + r) >> 1;
        pushdown(o);
        release(lson, l, mid);
        release(rson, mid + 1, r);
    }
}T;
int main()
{
    scanf("%d%d",&n,&m);
    for(int i = 1;i <= n; ++i) 
    { 
        int c; scanf("%d",&c);
        p[i] = i, root[i] = c, siz[i] = 1, tag_root[i] = 1;
    }  
    for(int i = 2;i <= m + 1; ++i)
    {  
        int opt, l, r, x; 
        scanf("%d%d%d%d",&opt,&l,&r,&x); 
        switch(opt) 
        {
            case 1:
                T.update(1, n, l, r, x, i, 1);
                break;
            case 2:
                int a = find(l), b = find(r);
                root[b] = x, tag_root[b] = i;
                if(a != b) { p[a] = b, siz[b] += siz[a]; }
                break;
        }
    }
    T.release(1, 1, n);
    T.release(1, 1, n);
    for(int i = 1;i <= n; ++i) printf("%d ",ans[i]);
    printf("\n");
    for(int i = 1;i <= n; ++i)
    {
        int x = find(i);
        printf("%d ",siz[x] - 1);
    }
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值