• BZOJ 4129 树上带修莫队+线段树


    思路:
    可以先做做BZOJ3585 是序列上的mex
    考虑莫队的转移 如果当前数字出现过 线段树上把它置成1
    对于询问 二分ans 线段树上查 0到ans的和 是不是ans+1
    本题就是把它搞到了序列上 带了个修改…
    麻烦一点 本质上是一样的

    //By SiriusRen
    #include <cmath>
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std;
    const int N=55555;
    int n,m,cnt=1,Block,block[N],op,xx,yy,a[N],vis[N],last[N],sum[N],tree[N*8];
    int first[N],next[N*2],v[N*2],tot,s[N],top,fa[N][20],cnt1,cnt2,deep[N],Ans[N];
    void add(int x,int y){v[tot]=y,next[tot]=first[x],first[x]=tot++;}
    void dfs(int x){
        for(int i=first[x];~i;i=next[i])
            if(v[i]!=fa[x][0])
                deep[v[i]]=deep[x]+1,fa[v[i]][0]=x,dfs(v[i]);
        s[++top]=x;
        if(top==Block){
            for(int i=1;i<=top;i++)block[s[i]]=cnt;
            cnt++,top=0;
        }
    }
    struct Ask{
        int time,id,l,r;Ask(){}
        Ask(int T,int I,int L,int R){time=T,id=I,l=L,r=R;}
        friend bool operator<(Ask a,Ask b){
            if(block[a.l]==block[b.l]){
                if(block[a.r]==block[b.r])return a.time<b.time;
                return block[a.r]<block[b.r];
            }return block[a.l]<block[b.l];
        }
    }ask[N];
    struct Change{
        int last,position,num;Change(){}
        Change(int L,int P,int nn){last=L,position=P,num=nn;}
    }change[N];
    void insert(int l,int r,int pos,int num,int f){
        if(l==r){tree[pos]=f;return;}
        int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
        if(mid<num)insert(mid+1,r,rson,num,f);
        else insert(l,mid,lson,num,f);
        tree[pos]=tree[lson]+tree[rson];
    }
    int query(int l,int r,int pos,int L,int R){
        if(l>=L&&r<=R)return tree[pos];
        int mid=(l+r)>>1,lson=pos<<1,rson=pos<<1|1;
        if(mid<L)return query(mid+1,r,rson,L,R);
        else if(mid>=R)return query(l,mid,lson,L,R);
        else return query(l,mid,lson,L,R)+query(mid+1,r,rson,L,R);
    }
    void reverse(int x){
        vis[x]^=1;
        if(a[x]<=n){
            if(vis[x]){
                sum[a[x]]++;
                if(sum[a[x]]==1)insert(0,n,1,a[x],1);
            }
            else{
                sum[a[x]]--;
                if(!sum[a[x]])insert(0,n,1,a[x],0);
            }
        }
    }
    void change_color(int x,int y){
        if(vis[x])reverse(x),a[x]=y,reverse(x);
        else a[x]=y;
    }
    void work(int x,int y){
        while(x!=y){
            if(deep[x]<deep[y])swap(x,y);
            reverse(x),x=fa[x][0];
        }
    }
    int lca(int x,int y){
        if(deep[x]<deep[y])swap(x,y);
        for(int i=19;i>=0;i--)if(deep[x]-(1<<i)>=deep[y])x=fa[x][i];
        if(x==y)return x;
        for(int i=19;i>=0;i--)if(fa[x][i]!=fa[y][i])x=fa[x][i],y=fa[y][i];
        return fa[x][0];
    }
    bool check(int x){
        return query(0,n,1,0,x)==x+1;
    }
    int main(){
        memset(first,-1,sizeof(first));
        scanf("%d%d",&n,&m),Block=sqrt(n);
        for(int i=1;i<=n;i++)scanf("%d",&a[i]),last[i]=a[i];
        for(int i=1;i<n;i++)scanf("%d%d",&xx,&yy),add(xx,yy),add(yy,xx);
        dfs(1);
        for(int i=1;i<=top;i++)block[s[i]]=cnt;
        for(int j=1;j<=19;j++)
            for(int i=1;i<=n;i++)
                fa[i][j]=fa[fa[i][j-1]][j-1];
        while(m--){
            scanf("%d%d%d",&op,&xx,&yy);
            if(op==1){
                if(block[xx]>block[yy])swap(xx,yy);
                ask[++cnt1]=Ask(cnt2,cnt1,xx,yy);
            }
            else change[++cnt2]=Change(last[xx],xx,yy),last[xx]=yy;
        }
        sort(ask+1,ask+1+cnt1);
        for(int i=1,T=0;i<=cnt1;i++){
            for(;T<ask[i].time;T++){
                change_color(change[T+1].position,change[T+1].num);
                a[change[T+1].position]=change[T+1].num;
            }
            for(;T>ask[i].time;T--){
                change_color(change[T].position,change[T].last);
                a[change[T].position]=change[T].last;
            }
            if(i!=1)work(ask[i-1].l,ask[i].l),work(ask[i-1].r,ask[i].r);
            else work(ask[i].l,ask[i].r);
            reverse(lca(ask[i].l,ask[i].r));
            int l=0,r=n,ans=0;
            while(l<=r){
                int mid=(l+r)>>1;
                if(check(mid))ans=mid+1,l=mid+1;
                else r=mid-1;
            }
            Ans[ask[i].id]=ans;
            reverse(lca(ask[i].l,ask[i].r));
        }
        for(int i=1;i<=cnt1;i++)printf("%d
    ",Ans[i]);
    }
  • 相关阅读:
    安装和强行卸载fuse
    Elasticsearch snapshot 备份的使用方法 【备忘】
    MYSQL数据仓库infobright【备忘】
    Tomcat8 启动慢 Creation of SecureRandom instance for session ID generation using [SHA1PRNG] took [53,161] milliseconds
    python爬虫实例
    JDK1.8 JVM参数配置
    QQ登录用到的URL
    CAS5.3.X 配置备忘
    Nexus3忘记admin密码时的解决办法
    CentOS7利用systemctl添加自定义系统服务
  • 原文地址:https://www.cnblogs.com/SiriusRen/p/6532022.html
Copyright © 2020-2023  润新知