HDU 3397 线段树

WA了好几发。。。细节颇多,总之写线段树就要写好pushdown和pushup函数

拍了300组数据才找到错误- -||新技能Get

#include"cstdio"
#include"queue"
#include"cmath"
#include"stack"
#include"iostream"
#include"algorithm"
#include"cstring"
#include"queue"
#include"map"
#include"vector"
#define ll long long
#define mems(a,b) memset(a,b,sizeof(a))
#define ls pos<<1
#define rs pos<<1|1

using namespace std;
const int MAXN = 1e5+50;
const int MAXE = 200500;
const int INF = 0x3f3f3f;

struct Node{
    int l,r;
    int num[2];
    int lazy[3];///0为置零1为置一2为翻转
    int lc[2][2];///最大left/right连续长度
    int mc[2];    ///最大长度
}node[MAXN<<2];
int x[MAXN];

void pushup(int pos){
    for(int i=0;i<2;i++) node[pos].num[i]=node[ls].num[i]+node[rs].num[i];
    int l=node[pos].l,r=node[pos].r,mid=(l+r)>>1;

    for(int i=0;i<2;i++){
        if(node[ls].num[i]==mid-l+1) node[pos].lc[0][i]=node[ls].num[i]+node[rs].lc[0][i];  ///只有在左区间全为0或1时才能这样更新
        else node[pos].lc[0][i]=node[ls].lc[0][i];
    }
    for(int i=0;i<2;i++){
        if(node[rs].num[i]==r-mid) node[pos].lc[1][i]=node[rs].num[i]+node[ls].lc[1][i];    ///同上
        else node[pos].lc[1][i]=node[rs].lc[1][i];
    }

    for(int i=0;i<2;i++) node[pos].mc[i]=max(node[ls].mc[i],node[rs].mc[i]);
    for(int i=0;i<2;i++) node[pos].mc[i]=max(node[pos].mc[i],node[ls].lc[1][i]+node[rs].lc[0][i]);///可以是左右区间的最大个数,也可能是连接后的个数
}

void pushdown(int pos){
    for(int i=0;i<2;i++)
        if(node[pos].lazy[i]){
            node[ls].lazy[i]=node[rs].lazy[i]=node[pos].lazy[i];
            node[ls].lazy[!i]=node[ls].lazy[2]=0;
            node[ls].mc[i]=node[ls].num[i]=node[ls].r-node[ls].l+1;
            node[ls].mc[!i]=node[ls].num[!i]=0;

            node[rs].lazy[!i]=node[rs].lazy[2]=0;
            node[rs].mc[i]=node[rs].num[i]=node[rs].r-node[rs].l+1;
            node[rs].mc[!i]=node[rs].num[!i]=0;
            for(int j=0;j<2;j++){
                node[ls].lc[j][i]=node[ls].r-node[ls].l+1;
                node[ls].lc[j][!i]=0;
                node[rs].lc[j][i]=node[rs].r-node[rs].l+1;
                node[rs].lc[j][!i]=0;
            }
        for(int i=0;i<3;i++) node[pos].lazy[i]=0;   ///如果已经置数,那么翻转标记就无用了
        }
    if(node[pos].lazy[2]){
        node[ls].lazy[2]^=1;
        node[rs].lazy[2]^=1;    ///写成直接=node[pos].lazy[2]WA了半天 - -||

        swap(node[ls].mc[0],node[ls].mc[1]);
        swap(node[ls].num[0],node[ls].num[1]);
        swap(node[ls].lazy[0],node[ls].lazy[1]);

        swap(node[rs].mc[0],node[rs].mc[1]);
        swap(node[rs].num[0],node[rs].num[1]);
        swap(node[rs].lazy[0],node[rs].lazy[1]);
        for(int i=0;i<2;i++){
            swap(node[ls].lc[i][0],node[ls].lc[i][1]);
            swap(node[rs].lc[i][0],node[rs].lc[i][1]);
        }
        node[pos].lazy[2]=0;
    }
}

void build(int l,int r,int pos){
    node[pos].l=l;
    node[pos].r=r;
    for(int i=0;i<3;i++) node[pos].lazy[i]=0;
    if(l==r){
        node[pos].num[x[l]]=1;
        node[pos].num[!x[l]]=0;
        node[pos].mc[x[l]]=1;
        node[pos].mc[!x[l]]=0;
        for(int i=0;i<2;i++){
            node[pos].lc[i][x[l]]=1;
            node[pos].lc[i][!x[l]]=0;
        }
        return;
    }
    int mid=(l+r)>>1;
    build(l,mid,ls);
    build(mid+1,r,rs);
    pushup(pos);
}

void update(int l,int r,int pos,int kind){
    if(l<=node[pos].l&&node[pos].r<=r){
        if(kind==2){
            node[pos].lazy[kind]^=1;
            swap(node[pos].mc[0],node[pos].mc[1]);
            swap(node[pos].num[0],node[pos].num[1]);
            swap(node[pos].lazy[0],node[pos].lazy[1]);
            for(int i=0;i<2;i++) swap(node[pos].lc[i][0],node[pos].lc[i][1]);
        }
        else if(!node[pos].lazy[kind]){
            node[pos].lazy[kind]=1;
            node[pos].lazy[!kind]=0;
            node[pos].lazy[2]=0;
            node[pos].mc[kind]=node[pos].num[kind]=node[pos].r-node[pos].l+1;
            node[pos].mc[!kind]=node[pos].num[!kind]=0;
            for(int j=0;j<2;j++){
                node[pos].lc[j][kind]=node[pos].r-node[pos].l+1;
                node[pos].lc[j][!kind]=0;
            }
        }
        return;
    }
    pushdown(pos);
    int mid=(node[pos].l+node[pos].r)>>1;
    if(l<=mid) update(l,r,ls,kind);
    if(r>mid) update(l,r,rs,kind);
    pushup(pos);
}

int queryone(int l,int r,int pos){
    int ans=0;
    if(l<=node[pos].l&&node[pos].r<=r){
        return node[pos].num[1];
    }
    pushdown(pos);
    int mid=(node[pos].l+node[pos].r)>>1;
    if(l<=mid) ans+=queryone(l,r,ls);
    if(r>mid) ans+=queryone(l,r,rs);
    return ans;
}

int query_maxlen(int l,int r,int pos){
    if(l==node[pos].l&&node[pos].r==r){
        return node[pos].mc[1];
    }
    pushdown(pos);
    int mid=(node[pos].l+node[pos].r)>>1;
    if(r<=mid) return query_maxlen(l,r,ls);
    else if(l>mid) return query_maxlen(l,r,rs);
    else {
        int ans=max(query_maxlen(l,mid,ls),query_maxlen(mid+1,r,rs));
        int a=min(node[ls].lc[1][1],mid-l+1);
        int b=min(node[rs].lc[0][1],r-mid);
        ans=max(ans,a+b);
        return ans;
    }
}
int main(){
    //freopen("in.txt","r",stdin);
    //freopen("pending.txt","w",stdout);
    int n,m,T;scanf("%d",&T);
    while(T--){
        scanf("%d%d",&n,&m);
        for(int i=0;i<n;i++) scanf("%d",&x[i]);
        build(0,n-1,1);
        int a,b,op;
        for(int i=0;i<m;i++){
            scanf("%d%d%d",&op,&a,&b);
            if(op==0||op==1||op==2) update(a,b,1,op);
            else if(op==3) printf("%d\n",queryone(a,b,1));
            else if(op==4) printf("%d\n",query_maxlen(a,b,1));
        }
    }
    return 0;
}

时间: 2024-10-06 06:42:39

HDU 3397 线段树的相关文章

HDU 3397 线段树 双懒惰标记

这个是去年遗留历史问题,之前思路混乱,搞了好多发都是WA,就没做了 自从上次做了大白书上那个双重懒惰标记的题目,做这个就思路很清晰了 跟上次大白上那个差不多,这个也是有一个sets标记,代表这个区间全部置为0或者1,没有置位的时候为-1 还有个rev标记,代表翻转操作,0代表当前不翻,1代表当前翻 要注意一下优先级,发现有不同的弄法,我是这个弄得,有set操作的时候,set标记设值,并把当前节点的rev标记设为0,因为不管要不要rev,当前set操作肯定直接覆盖了 rev操作不改变set操作,在

HDU 3397 线段树区间修改

Sequence operation Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 8308    Accepted Submission(s): 2507 Problem Description lxhgww got a sequence contains n characters which are all '0's or '1'

HDU 4893 线段树裸题

Wow! Such Sequence! Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65536/65536 K (Java/Others) Total Submission(s): 2512    Accepted Submission(s): 751 Problem Description Recently, Doge got a funny birthday present from his new friend, Pro

HDU 4902 线段树(区间更新)

Nice boat Time Limit: 30000/15000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 353    Accepted Submission(s): 169 Problem Description There is an old country and the king fell in love with a devil. The devil alw

hdu 4893 线段树 --- 也是两个变 类似双标记

http://acm.hdu.edu.cn/showproblem.php?pid=4893 开始的时候,我按双标记,WA了一下午,搞不定,我是用的两个标记add--表示当前结点中有值发生变化,flag,斐波那契的懒惰标记,但是估计是我自己处理的有问题,一直不对 参考了别人的代码,写法还是很不错的,Add变量维护的是,完全变成Fibonacci的时候的和,---回头我再重新写一遍 #include <cstdio> #include <cstring> #include <a

HDU 4902 线段树||暴力

给定一个序列,两种操作 1:把一段变成x. 2:把一段每个数字,如果他大于x,就变成他和x的gcd,求变换完后,最后的序列. 线段树解法:用lazy标记下即可,优化方法还是很巧妙的, Accepted 4902 515MS 3308K 1941 B C++ #include "stdio.h" #include "string.h" struct node { int l,r,x;// 在叶子节点代表值,树节点代表成端更新的lazy操作. }data[400010]

HDU 4302 线段树单点更新,维护区间最大最小值

http://acm.hdu.edu.cn/showproblem.php?pid=4302 Problem Description Holedox is a small animal which can be considered as one point. It lives in a straight pipe whose length is L. Holedox can only move along the pipe. Cakes may appear anywhere in the p

hdu 2795 线段树--点更新

http://acm.hdu.edu.cn/showproblem.php?pid=2795 多校的第一场和第三场都出现了线段树,比赛期间没做,,这两天先做几道热身下,然后31号之前把那两道多校的线段树都搞了,这是一道热身题 关键是建模: 首先一定看清楚题目构造的场景,看有什么特点--------会发现,如果尽量往左上放置的话,那么由于 the i-th announcement is a rectangle of size 1 * wi.,完全可以对h建立线段树,表示一行,结点里的l,r就表示

HDU 1698 线段树(区间染色)

Just a Hook Time Limit: 4000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Submission(s): 16255    Accepted Submission(s): 8089 Problem Description In the game of DotA, Pudge’s meat hook is actually the most horrible thing f