LDUOJ 时间锁链 (状压+线段树 )

简介: LDUOJ 时间锁链 (状压+线段树 )

时间锁链

时间限制: 1 Sec 内存限制: 128 MB

[命题人:admin] [ Edit] [ TestData]

题目描述

当墨老师找到封闭时间环中最小的逆序对数后,他就可以将时间环展开成一个长L的时间锁链(我们可以将之看成是一根很长的管子),其中L是整数,所以我们可以将该管子分为L段,并从左到右标记为1,2,…,L。


现在对管子有两种操作:


“C A B C” 将A到B的数都标记为C(我们可形象的看成是染成C这种颜色)。


“P A B” 输出A和B之间不同颜色的数目。


颜色有T种,标记为1,2,3…,T,T是一个很小的值,初始时管子的颜色为1。

输入

第一行为L (1≤L≤100 000),T (1≤T≤30)和O (1≤O≤100 000),其中O表示操作数。随后O行为操作命令即"C A B C"或"P A B",其中A可能比B值大。

输出

输出操作的结果。

样例输入 Copy

2 2 4

C 1 1 2

P 1 2

C 2 2 2

P 1 2

样例输出 Copy

2

1


题意:

题意很简单,给你一个区间和两种操作,你可以更改区间的数或是查询区间里有多少种不同的数。

思路:

典型的区间修改和区间查询,用线段树维护一下就可以了。

因为颜色的总数目很小,我们可以开一个bool数组暴力记录(应该可以~),也可以把状态压缩成二进制数,表示的含义就是第i位为1时说明第i个颜色被涂上了。


代码:

注意一下pushdown的写法~

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e6+7;
struct node{
    int l,r;
    int sum;//二进制表示涂了多少种颜色
    int lazy;
}a[maxn];
void pushdown(int u){
    if(a[u].lazy){
        a[u<<1].lazy=a[u<<1|1].lazy=a[u].lazy;
        a[u<<1].sum=a[u<<1|1].sum=(1<<a[u].lazy);
        a[u].lazy=0;
    }
}
void build(int u,int l,int r){
    a[u].l=l;a[u].r=r;
    if(l==r) a[u].sum=1<<1;
    else{
        int mid=(l+r)>>1;
        build(u<<1,l,mid);
        build(u<<1|1,mid+1,r);
        a[u].sum=a[u<<1].sum|a[u<<1|1].sum;
    }
}
void update(int u,int z,int l,int r){
    if(a[u].l>r||a[u].r<l) return ;///完全不包含
    if(a[u].l>=l&&a[u].r<=r){//完全包含
        a[u].sum=1<<z;
        a[u].lazy=z;
        return ;
    }
    pushdown(u);
    update(u<<1,z,l,r);update(u<<1|1,z,l,r);
    a[u].sum=a[u<<1].sum|a[u<<1|1].sum;
}
int query(int u,int l,int r){
    if(a[u].l>r||a[u].r<l) return 0;
    if(a[u].l>=l&&a[u].r<=r) return a[u].sum;
    pushdown(u);
    return query(u<<1,l,r)|query(u<<1|1,l,r);
}
int main(){
    int n,t,o;
    cin>>n>>t>>o;
    build(1,1,n);
    while(o--){
        char op;int x,y;
        cin>>op>>x>>y;
        if(op=='P'){
            if(x>y) swap(x,y);
            int res=query(1,x,y);
            int sum=0;
            for(int i=1;i<=t;i++)
                if(res&(1<<i)) sum++;
            cout<<sum<<endl;
        }
        else if(op=='C'){
            int z;
            if(x>y) swap(x,y);
            cin>>z;
            update(1,z,x,y);
        }
    }
    return 0;
}
目录
相关文章
|
3天前
|
算法 测试技术 C#
【二分查找】【区间合并】LeetCode2589:完成所有任务的最少时间
【二分查找】【区间合并】LeetCode2589:完成所有任务的最少时间
|
3天前
leetcode746使用最小花费爬楼梯刷题打卡
leetcode746使用最小花费爬楼梯刷题打卡
15 0
|
3天前
|
算法 测试技术 C++
【动态规划】【图论】【C++算法】1928规定时间内到达终点的最小花费
【动态规划】【图论】【C++算法】1928规定时间内到达终点的最小花费
|
3天前
leetcode代码记录(使用最小花费爬楼梯
leetcode代码记录(使用最小花费爬楼梯
10 0
|
3天前
|
C++
2589. 完成所有任务的最少时间(区间取点——贪心or线段树)
2589. 完成所有任务的最少时间(区间取点——贪心or线段树)
|
3天前
动态规划之使用最小花费爬楼梯【LeetCode】
动态规划之使用最小花费爬楼梯【LeetCode】
|
3天前
|
Java 索引
leetcode-746:使用最小花费爬楼梯
leetcode-746:使用最小花费爬楼梯
22 0
|
3天前
|
人工智能
牛客xiao白月赛39 D(线段树维护区间)
牛客xiao白月赛39 D(线段树维护区间)
16 0
|
9月前
|
测试技术
动态规划之使用最小花费爬楼梯
动态规划之使用最小花费爬楼梯
|
10月前
|
算法
【学会动态规划】使用最小花费爬楼梯(3)
【学会动态规划】使用最小花费爬楼梯(3)
77 1