[2018雅礼省选集训4-2]Problem A 位运算+势能分析线段树

14人阅读 评论(0) 收藏 举报
分类:

首先把看成把某些位强制变为0,把看成把某些位强制变为1。那么对于一次修改,如果一个区间内的数这些位都相同就打标记,否则暴力处理左右区间即可。
先证明这样做的复杂度是对的,设fi=flsoni+frsoni+k=020[ik],那么f(root)一开始是O(20N)的,每次修改最多增加O(20logN),而每次访问一个新节点f(root)至少减少1,所以复杂度是O(20NlogN)的。
至于打标记,可以用一个与标记和一个或标记来表示(注意认为规定先后顺序),判断一些位是否全相同,可以维护区间与和、区级或和,与和为1或者或和为0的位就是全相同的了。
代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#define mid (l+r>>1)
#define N 200010
using namespace std;
const int R=(1<<20)-1;
int n,q,a[N];
int read()
{
    int x=0,f=1;char ch=getchar();
    for(;ch<'0'||ch>'9';ch=getchar()) if(ch=='-') f=-1;
    for(;ch>='0'&&ch<='9';ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
struct tree
{
    int mx,h,y,bh,by;
    tree *ls,*rs;
    tree(){h=0;y=R;}
    void update()
    {
        mx=max(ls->mx,rs->mx);
        bh=ls->bh|rs->bh;
        by=ls->by&rs->by;
    }
    void cal(int dh,int dy)
    {
        mx=(mx&dy)|dh;bh=(bh&dy)|dh;by=(by&dy)|dh;
        y=(y&dy);h=(h&dy)|dh;
    }
    void pushdown()
    {
        ls->cal(h,y);
        rs->cal(h,y);
        h=0;y=R;
    }
    void build(int l,int r)
    {
        if(l==r) {mx=bh=by=a[l];return ;}
        (ls=new tree)->build(l,mid);
        (rs=new tree)->build(mid+1,r);
        update();
    }
    void mdf(int l,int r,int lx,int rx,int dh,int dy)
    {
        if(l==lx&&r==rx)
        {
            int t=(by|(R^bh));
            if(((dh|t)==t)&&(((R^dy)|t)==t)) {cal(dh,dy);return ;} 
        }
        pushdown();
        if(rx<=mid) ls->mdf(l,mid,lx,rx,dh,dy);
        else if(lx>mid) rs->mdf(mid+1,r,lx,rx,dh,dy);
        else ls->mdf(l,mid,lx,mid,dh,dy),rs->mdf(mid+1,r,mid+1,rx,dh,dy);
        update();
    }
    int qry(int l,int r,int lx,int rx)
    {
        if(l==lx&&r==rx) return mx;
        pushdown();
        if(rx<=mid) return ls->qry(l,mid,lx,rx);
        if(lx>mid) return rs->qry(mid+1,r,lx,rx);
        return max(ls->qry(l,mid,lx,mid),rs->qry(mid+1,r,mid+1,rx)); 
    }
}*xtr;
int main()
{
    n=read();q=read();
    for(int i=1;i<=n;i++)
        a[i]=read();
    (xtr=new tree)->build(1,n); 
    while(q--)
    {
        int opt=read(),l=read(),r=read(),x;
        if(opt==1)  xtr->mdf(1,n,l,r,0,read());
        if(opt==2)  xtr->mdf(1,n,l,r,read(),R);
        if(opt==3)  printf("%d\n",xtr->qry(1,n,l,r));
    }
    return 0;
}
查看评论

[2018雅礼集训1-12]小C的线段树 DP

题面 考虑当n>mn>m时答案为00,1≤nm≤1051\le nm \le 10^5,所以只用考虑n1052n的情况。 把一个区间看成一对括号,设fi,l,rf_{i,l,r}表示前ii个点,之...
  • DOFYPXY
  • DOFYPXY
  • 2018-01-17 22:14:21
  • 160

雅礼集训酱油记(2017-01-11~2017-01-23)

一句话:知道了自己有多弱。。。讲课: 第一天就完全懵逼了,毛爷爷的DP除了学过的听懂了一半,没学过的东西(Knuth、单调性、三分、凸包??)单词都认不到。。。酱油过去。 数据结构还算听懂得比较多...
  • can919
  • can919
  • 2017-01-24 21:59:00
  • 509

雅礼集训1.4 序列

标签:迭代加深搜索,IDA* 题目 序列(sequence) 【题目描述】 给定一个1~n的排列x,每次你可以将x1~xi翻转。你需要求出将序列变为升序的最小操作次数。有多组数据。 【输入数...
  • qwerty1125
  • qwerty1125
  • 2018-01-05 17:43:05
  • 116

「雅礼集训 2017 Day2」水箱 并查集+树形DP

前言 好久没有写博客了,写一道雅礼毒瘤题来开开刀……CSDN都转变编辑器风格了,那我也顺便转换一下写作风格啦~ 题目链接 水箱-LOJ 题目描述(改编) 有一个毒瘤,长得和水箱一样,可以装很...
  • C20190101ZJX
  • C20190101ZJX
  • 2018-01-07 11:33:53
  • 179

LOJ 6032 「雅礼集训 2017 Day2」水箱

线段树合并+树状数组把0设成-1,问题就变成求最大前缀和。考虑一个DP,记f[i]表示i隔板隔住了水,i之前最多满足多少条件。转移的时候枚举j表示[j,i]能是一个以j,i为左右端点的装水区间。这样的...
  • ziqian2000
  • ziqian2000
  • 2017-06-28 07:54:54
  • 344

[2018雅礼集训1-10]Function 积性函数前缀和

题面 题目要我们求 ∑i=1n∑d|iμ(d)∗σ20(id)\sum_{i=1}^n\sum_{d|i}\mu(d)*\sigma_0^2(\frac{i}{d}) 设f(i)=∑d|iμ(d...
  • DOFYPXY
  • DOFYPXY
  • 2018-01-11 22:18:08
  • 165

[2018雅礼集训1-16]序列 爆搜+贪心

题面 首先问题转化为选取一个(Mi,Vi)(M_i,V_i)的集合,该集合必须满足若Mk|lcm{Mi}M_k|lcm\{M_i\},(Mk,Vk)(M_k,V_k)必须在集合中,最大化∑Vi\su...
  • DOFYPXY
  • DOFYPXY
  • 2018-01-18 20:51:14
  • 101

[2018雅礼集训1-20]B 分块

题面 考虑把序列分成N−−√\sqrt N块,记cnti,jcnt_{i,j}表示第ii块颜色jj的个数,设si,js_{i,j}为i,ji,j两块之间产生的贡献,通过cntcnt可以O(N−−√)...
  • DOFYPXY
  • DOFYPXY
  • 2018-01-20 20:34:31
  • 127

雅礼集训及WC2018划水记

雅礼集训1.30~2.3 noip考成250,没得去thuwc和pkuwc,和czy等去参加本来只有samjia和栋栋的集训队模拟。抱着被虐的心态去比赛。 第一天刚到比较困,比赛有点没精神,看到t...
  • ZLTJohn
  • ZLTJohn
  • 2018-02-12 22:25:15
  • 152
    个人资料
    持之以恒
    等级:
    访问量: 2万+
    积分: 2408
    排名: 1万+
    最新评论