Bzoj1493--Noi2007项链工厂

真?恶心,代码题就是痛苦

我的想法是先双倍展开后线段树维护,双倍展开后Print和Swap的操作对于前后两边都要做一次,调了半天

前两个操作可以不动线段树而把他询问的坐标转化到正确坐标即可

代码 :

#include<bits/stdc++.h>
using namespace std;

#define MAXN 500005

int n,c,cl[MAXN*2];
int q,Tf,Tv;
char qe[4];

inline int Tran(int x) {return Tf?((n-(x+Tv))%n+n)%n:(x+Tv)%n;}

namespace SegmentTree{
    const int L=0,R=1;
    struct node{
        int son[2],be,nd,cs,set;
    }x[MAXN*4];
    int sz=1;

    inline void updata(int num) {
        x[num].be=x[x[num].son[L]].be;
        x[num].nd=x[x[num].son[R]].nd;
        x[num].cs=x[x[num].son[L]].cs+x[x[num].son[R]].cs;
        if(x[x[num].son[L]].nd==x[x[num].son[R]].be) x[num].cs--;
    }
    inline void Set(int num,int tc) {
        x[num].be=x[num].nd=x[num].set=tc;x[num].cs=1;
    }
    inline void maintain(int num) {
        Set(x[num].son[L],x[num].set);
        Set(x[num].son[R],x[num].set);
        x[num].set=0;
    }
    node Merge(node a,node b) {
        node ret;
        ret.be=a.be;ret.nd=b.nd;
        ret.cs=a.cs+b.cs;
        if(a.nd==b.be) ret.cs--;
        return ret;
    }

    void _init(int l,int r,int num) {
        if(l==r) {
            x[num].be=x[num].nd=cl[l];
            x[num].cs=1;return;
        }
        int mid=l+r>>1;
        x[num].son[L]=++sz;x[num].son[R]=++sz;
        _init(l,mid,x[num].son[L]);_init(mid+1,r,x[num].son[R]);
        updata(num);
    }

    void Print(int l,int r,int nl,int nr,int num,int tc) {
        if(l==nl&&r==nr) {Set(num,tc);return;}
        int mid=l+r>>1;
        if(x[num].set) maintain(num);
        if(nl>mid) Print(mid+1,r,nl,nr,x[num].son[R],tc);
        else if(nr<=mid) Print(l,mid,nl,nr,x[num].son[L],tc);
        else {
            Print(l,mid,nl,mid,x[num].son[L],tc);
            Print(mid+1,r,mid+1,nr,x[num].son[R],tc);
        }
        updata(num);
    }
    node TQurey(int l,int r,int nl,int nr,int num) {
        if(l==nl&&r==nr) return x[num];
        int mid=l+r>>1;node ret;
        if(nl>mid) ret=TQurey(mid+1,r,nl,nr,x[num].son[R]);
        else if(nr<=mid) ret=TQurey(l,mid,nl,nr,x[num].son[L]);
        else ret=Merge(TQurey(l,mid,nl,mid,x[num].son[L]),TQurey(mid+1,r,mid+1,nr,x[num].son[R]));
        if(x[num].set) {ret.be=ret.nd=x[num].set;ret.cs=1;}
        return ret;
    }
    int TColor(int p,int l,int r,int num) {
        if(l==r) return x[num].be;
        if(x[num].set) return x[num].set;
        int mid=l+r>>1;
        if(p>mid) return TColor(p,mid+1,r,x[num].son[R]);
        else return TColor(p,l,mid,x[num].son[L]);
    }

    inline int Qurey(int l,int r,bool cr) {
        if(l>r) swap(l,r);
        node ans=TQurey(0,2*n-1,l,r,1);
        if(cr&&ans.be==ans.nd&&ans.cs>1) ans.cs--;
        return ans.cs;
    }
    inline int Color(int p) {
        return TColor(p,0,2*n-1,1);
    }
}
#define ST SegmentTree

int main() {
    scanf("%d%d",&n,&c);
    for(int i=0;i<n;i++) scanf("%d",&cl[i]);
    for(int i=0;i<n;i++) cl[n+i]=cl[i];
    ST::_init(0,(n<<1)-1,1);
    scanf("%d",&q);
    for(int a,b,c,i=1;i<=q;i++) {
        scanf("%s",qe);
        if(qe[0]==‘R‘) {scanf("%d",&a);Tv=((Tv-a)%n+n)%n;}
        else if(qe[0]==‘F‘) {Tf^=1;Tv=((-Tv)%n+n)%n;}
        else if(qe[0]==‘C‘) {
            if(qe[1]==‘S‘) {
                scanf("%d%d",&a,&b);a--;b--;
                a=Tran(a);b=Tran(b);if(Tf) swap(a,b);
                if(b<a) b+=n;
                printf("%d\n",ST::Qurey(a,b,0));
            }
            else printf("%d\n",ST::Qurey(0,n-1,1));
        }
        else if(qe[0]==‘P‘) {
            scanf("%d%d%d",&a,&b,&c);a--;b--;
            a=Tran(a);b=Tran(b);if(Tf) swap(a,b);
            if(b<a) b+=n;
            ST::Print(0,2*n-1,a,b,1,c);
            if(b+n<2*n) ST::Print(0,2*n-1,a+n,b+n,1,c);
            else {
                ST::Print(0,2*n-1,a+n,2*n-1,1,c);
                ST::Print(0,2*n-1,0,(b+n)%n,1,c);
            }
        }
        else if(qe[0]==‘S‘) {
            scanf("%d%d",&a,&b);a--;b--;
            a=Tran(a);b=Tran(b);
            int t1=ST::Color(a),t2=ST::Color(b);
            ST::Print(0,2*n-1,a,a,1,t2);if(a+n<2*n) ST::Print(0,2*n-1,a+n,a+n,1,t2);
            ST::Print(0,2*n-1,b,b,1,t1);if(b+n<2*n) ST::Print(0,2*n-1,b+n,b+n,1,t1);
        }
        /*
        for(int i=0;i<2*n;i++) {
            printf("%d ",ST::Color(Tran(i)));
        }
        cout<<endl;
        */
    }
    return 0;
}
#undef ST
/*
7 4
1 3 3 3 3 1 1
100
F
R 2
P 1 7 1
*/
时间: 2024-08-24 15:10:41

Bzoj1493--Noi2007项链工厂的相关文章

BZOJ1493 [NOI2007]项链工厂

未完待续... 1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1320  Solved: 576[Submit][Status][Discuss] Description T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱. 最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链.该项链自助生产系 统包括硬件系统与软件系统,软件系统与

bzoj1493[NOI2007]项链工厂 线段树

1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1712  Solved: 723[Submit][Status][Discuss] Description T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱. 最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链.该项链自助生产系 统包括硬件系统与软件系统,软件系统与用户进行交互并控

BZOJ1493 NOI2007 项链工厂 线段树模拟

提交地址:http://www.lydsy.com/JudgeOnline/problem.php?id=1493 题目大意:给一个数列,进行一系列操作.包括旋转,翻转,改变等操作,以及查询颜色段数. 题目分析:数列中元素的相对位置没有改变,因此不需要用splay去做,而是可以用线段树解决这类问题. 旋转操作直接改变变量rotate,翻转操作用异或即可.每次询问先利用rotate求出当前1号位是谁,这样可以根据翻转标记确定区间.如果区间跨越n,那么合并的时候要考虑左边一段的右端和右边一段的左端.

【BZOJ-1493】项链工厂 Splay

1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1440  Solved: 626[Submit][Status][Discuss] Description T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱. 最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链.该项链自助生产系统包括硬件系统与软件系统,软件系统与用户进行交互并控制

bzoj 1493: [NOI2007]项链工厂(线段树)

1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MBSubmit: 1256  Solved: 545[Submit][Status][Discuss] Description Input 输 入文件第一行包含两个整数N, c,分别表示项链包含的珠子数目以及颜色 数目.第二行包含N 个整数,x1, x2…, xn,表示从位置1 到位置N 的珠子的颜色, 1 ≤ xi ≤ c.第三行包含一个整数Q,表示命令数目.接下来的Q 行每行一

数据结构(Splay平衡树): [NOI2007] 项链工厂

[NOI2007] 项链工厂 ★★★   输入文件:necklace.in   输出文件:necklace.out   简单对比 时间限制:4 s   内存限制:512 MB [问题描述] T公司是一家专门生产彩色珠子项链的公司,其生产的项链设计新颖.款式多样.价格适中,广受青年人的喜爱.最近T公司打算推出一款项链自助生产系统,使用该系统顾客可以自行设计心目中的美丽项链. 该项链自助生产系统包括硬件系统与软件系统,软件系统与用户进行交互并控制硬件系统,硬件系统接受软件系统的命令生产指定的项链.该

NOI2007项链工厂——sbTreap代码

1 2 #include <iostream> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cstring> 6 #include <cstdlib> 7 8 using namespace std; 9 struct node 10 { 11 int data; 12 int left; 13 int right; 14 int key; 15 int size; 16 bool

【BZOJ 1493】[NOI2007]项链工厂

1493: [NOI2007]项链工厂 Time Limit: 30 Sec  Memory Limit: 64 MB Submit: 992  Solved: 454 [Submit][Status] Description   Input 输入文件第一行包含两个整数N, c,分别表示项链包含的珠子数目以及颜色 数目.第二行包含N 个整数,x1, x2-, xn,表示从位置1 到位置N 的珠子的颜色, 1 ≤ xi ≤ c.第三行包含一个整数Q,表示命令数目.接下来的Q 行每行一条命令, 如上

1493: [NOI2007]项链工厂

线段树. 真还就是个线段树.. 除去操作1,2的话,线段树很容易就处理了,问题在于如何处理操作1和2.(这点没想到).. 我们用一个delta维护操作1,如果没有旋转就+k,不然就-k. 每次读入i和j的时候用trans处理一下,就成功在O(1)的时间解决了操作1和2. 细节很重要. #include<cstdio> #include<algorithm> #include<cstring> using namespace std; const int maxn = 2

BZOJ 1493 NOI2007 项链工厂

题目大意:维护一个环,每个点有一个颜色,提供6种操作: 1.将这个环顺时针旋转k 2.沿点1所在直径翻转 3.将两个珠子互换 4.将一段区间染色 5.查询这个环上有多少颜色段 6.查询一段区间有多少颜色段 关于颜色段通用的处理方法是每个区间记录三个值,颜色段数.左端点颜色.右端点颜色,合并时颜色段数相加,如果左区间右端点和右区间左端点颜色相同则减一 然后用Splay维护区间即可 不过这题还是有一些小细节需要处理 首先null节点要保证不会被修改 然后更新的时候特判 如果一段区间颜色是0直接返回另