POJ - 3225 Help with Intervals (区间置0/1与区间异或混合操作)

Help with Intervals

LogLoader, Inc. is a company specialized in providing products for analyzing logs. While Ikki is working on graduation design, he is also engaged in an internship at LogLoader. Among his tasks, one is to write a module for manipulating time intervals, which have confused him a lot. Now he badly needs your help.

In discrete mathematics, you have studied several basic set operations, namely union, intersection, relative complementation and symmetric difference, which naturally apply to the specialization of sets as intervals.. For your quick reference they are summarized in the table below:

OperationNotation

Definition

UnionA ∪ B{x : x ∈ A or x ∈ B}
IntersectionA ∩ B{x : x ∈ A and x ∈ B}
Relative complementationA − B{x : x ∈ A but B}
Symmetric differenceA ⊕ B(A − B) ∪ (B − A)

Ikki has abstracted the interval operations emerging from his job as a tiny programming language. He wants you to implement an interpreter for him. The language maintains a set S, which starts out empty and is modified as specified by the following commands:

CommandSemantics
U TS ← S ∪ T
I TS ← S ∩ T
D TS ← S − T
C TS ← T − S
S TS ← S ⊕ T

Input

The input contains exactly one test case, which consists of between 0 and 65,535 (inclusive) commands of the language. Each command occupies a single line and appears like

X T

where X is one of ‘U’, ‘I’, ‘D’, ‘C’ and ‘S’ and T is an interval in one of the forms (a,b)(a,b][a,b) and [a,b] (ab ∈ Z, 0 ≤ a ≤ b ≤ 65,535), which take their usual meanings. The commands are executed in the order they appear in the input.

End of file (EOF) indicates the end of input.

Output

Output the set S as it is after the last command is executed as the union of a minimal collection of disjoint intervals. The intervals should be printed on one line separated by single spaces and appear in increasing order of their endpoints. If S is empty, just print “empty set” and nothing else.

Sample Input

U [1,5]
D [3,3]
S [2,4]
C (1,5)
I (2,3]

Sample Output

(2,3)

题意:让模拟并、交、相对补、对称差。每一次都给定一个区间和操作类型,问最后区间是什么样子,用并的方式输出

思路:首先是括号'[' 和 '(' 的问题,这表明更新时 是更新一个区间,而不是区间上的端点,所以需要新插入一个点代表两点之前的段。 由于点是从 0 开始的,我采用的操作是  如端点 l , 先 ++ l,然后以 2 * l - 1 作为线段树的更新端点,这样原每两个相邻的点之间就会插入一个点。

  • 并:直接将 更新区间置1
  • 交:将更新区间的两边置0
  • 相对补:两边置0,更新区间所有值取异或
  • 对称差:更新区间所有值取异或

我一开始,只设置了一个 type 数组,表示区间是否是同一值。利用 type 直接更新到值相同的段,然后 T 了。

搜了一下题解,还需要用到 lazyXor 数组。

唯一 一个需要很理解的地方就是:如果当前区间是同一值,就对 type 数组操作 (因为最后查询的时候是查询 type 是否为 1),否则就只能对 lazyXor 操作。   对于 push_down 时,type 的优先级要大于 lazyXor,也就是 如果能够利用 type 进行push_down,就用type,同时还要将两个儿子的 lazyXor 置0 (因为这是直接赋值的,且type != -1 时,这个区间的 lazyXor 一定为 0)。置 0/1 时也要将 lazyXor 置0

贴上抄袭代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#define debug(x) cout << "[" << #x <<": " << (x) <<"]"<< endl
#define pii pair<int,int>
#define clr(a,b) memset((a),b,sizeof(a))
#define rep(i,a,b) for(int i = a;i < b;i ++)
#define pb push_back
#define MP make_pair
#define LL long long
#define ull unsigned LL
#define ls i << 1
#define rs (i << 1) + 1
#pragma GCC optimize(2)
#define INT(t) int t; scanf("%d",&t)

using namespace std;

const int maxn = 65536 * 2 + 10;
int type[maxn << 2];
int lazyXor[maxn << 2];
const int n = 65536 * 2 - 1;

void solve(int i){
    if(type[i] != -1){
        type[i] ^= 1;
        lazyXor[i] = 0;
    }
    else lazyXor[i] ^= 1;
}

void push_down(int l,int r,int i){
    if(type[i] != -1){
        type[ls] = type[rs] = type[i];
        lazyXor[ls] = lazyXor[rs] = 0;
        type[i] = -1;
    }
    else if(lazyXor[i] == 1){
        solve(ls);
        solve(rs);
        lazyXor[i] = 0;
    }
}

void update(int l,int r,int ul,int ur,int i,int UorI){
    if(ul > ur) return ;
    if(ul <= l && r <= ur){
        type[i] = UorI;
        lazyXor[i] = 0;
        return ;
    }
    push_down(l,r,i);
    int mid = (l + r) >> 1;
    if(ul <= mid) update(l,mid,ul,ur,i << 1,UorI);
    if(ur > mid) update(mid + 1,r,ul,ur,i << 1 | 1,UorI);
    type[i] = (type[i << 1] == type[i << 1 | 1] ? type[i << 1] : -1);
}

void updateC(int l,int r,int ul,int ur,int i){
    if(ul > ur) return ;
    if(ul <= l && r <= ur){
        solve(i);
        return ;
    }
    if(l == r) return ;
    push_down(l,r,i);
    int mid = (l + r) >> 1;
    if(ul <= mid) updateC(l,mid,ul,ur,i << 1);
    if(ur > mid) updateC(mid + 1,r,ul,ur,i << 1 | 1);

}

#define ok(x) (2 * (x) - 1)

bool query(int l,int r,int pos,int i){
    if(l == r)
        return type[i] == 1;
    push_down(l,r,i);
    int mid = (l + r) >> 1;
    if(pos <= mid) return query(l,mid,pos,i << 1);
    if(pos > mid) return query(mid + 1,r,pos,i << 1 | 1);
}

int main() {
    char ch;
    while(~scanf("%c",&ch)){
        char lef,rig;
        int l,r;
        scanf(" %c%d,%d%c",&lef,&l,&r,&rig);
        ++ l; ++ r;
        l = ok(l);
        r = ok(r);
        if(ch == 'U'){
            if(lef == '(') ++ l;
            if(rig == ')') -- r;
            update(1,n,l,r,1,1);/// 把中间的直接变成1
        }
        else if(ch == 'I'){     /// 把两边的全部变成0
            if(lef == '[') -- l;
            if(rig == ']') ++ r;
            update(1,n,1,l,1,0);
            update(1,n,r,n,1,0);
        }
        else if(ch == 'D'){
            if(lef == '(') ++ l;
            if(rig == ')') -- r;
            update(1,n,l,r,1,0);
        }
        else if(ch == 'C'){
            if(lef == '[') -- l;
            if(rig == ']') ++ r;
            update(1,n,1,l,1,0);
            update(1,n,r,n,1,0);
            ++ l;
            -- r;
            updateC(1,n,l,r,1);
        }
        else {
            if(lef == '(') ++ l;
            if(rig == ')') -- r;
            updateC(1,n,l,r,1);
        }
        getchar();
    }
    int coun = 0;
        int Beg = maxn,END;
        char Lef,Rig;
        for(register int i = 1;i <= n + 1;++ i){
            int tttmp = i == n + 1 ? 0 : query(1,n,i,1);
            if(tttmp){
                END = (i + 1) / 2 - 1;
                Rig = i % 2 == 1 ? ']':')';
                if(Beg > END){
                    Beg = END;
                    Lef = i % 2 == 1 ? '[':'(';
                }
                ++ coun;
            }
            else if(!tttmp || i == n + 1){
                if(coun && Beg != maxn) printf("%c%d,%d%c ",Lef,Beg,END + (i % 2 == 1),Rig);
                Beg = maxn;
            }
        }
        if(coun == 0) printf("empty set");
        printf("\n");
    return 0;
}

 

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
POJ - 3616是一个题目,题目描述如下: 给定一组区间,每个区间有一个权重,要求选择一些区间,使得这些区间的右端点都小于等于k,并且权重之和最大。请问最大的权重和是多少? 解决这个问题的思路是使用动态规划。首先,将区间按照左端点从小到大进行排序。然后,定义一个dp数组,dp[i]表示右端点小于等于i的所有区间所能得到的最大权重。 接下来,遍历每一个区间,对于每个区间i,将dp[i]初始化为区间i的权重。然后,再遍历i之前的每个区间j,如果区间j的右端点小于等于k,并且区间j的权重加上区间i的权重大于dp[i],则更新dp[i]为dp[j]加上区间i的权重。 最后,遍历整个dp数组,找到最大的权重和,即为所求的答案。 下面是具体的代码实现: ```cpp #include <cstdio> #include <cstring> #include <algorithm> using namespace std; struct interval{ int start, end, weight; }; interval intervals[10005]; int dp[10005]; int n, m, k; bool compare(interval a, interval b) { if (a.start == b.start) { return a.end < b.end; } else { return a.start < b.start; } } int main() { while(~scanf("%d %d %d", &n, &m, &k)) { memset(dp, 0, sizeof dp); for (int i = 0; i < m; i++) { scanf("%d %d %d", &intervals[i].start, &intervals[i].end, &intervals[i].weight); } sort(intervals, intervals + m, compare); for (int i = 0; i < m; i++) { dp[i] = intervals[i].weight; for (int j = 0; j < i; j++) { if (intervals[j].end <= k && dp[j] + intervals[i].weight > dp[i]) { dp[i] = dp[j] + intervals[i].weight; } } } int maxWeight = 0; for (int i = 0; i < m; i++) { maxWeight = max(maxWeight, dp[i]); } printf("%d\n", maxWeight); } } ```

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值