zoukankan      html  css  js  c++  java
  • BZOJ1146:[CTSC2008]网络管理

    浅谈树状数组与线段树:https://www.cnblogs.com/AKMer/p/9946944.html

    题目传送门:https://www.lydsy.com/JudgeOnline/problem.php?id=1146

    在欧拉序上用树状数组套权值线段树搞事情。在进的时候加一,出去的时候减一。

    从欧拉序第一位到当前点的(L)就是根到当前点的状态(因为其他的路径一进一出抵消掉了),然后你求出两个点的(lca)(lca)的父亲减一减跑一跑就好了。

    时间复杂度:(O(nlog^2n))

    空间复杂度:(O(nlog^2n))

    代码如下:

    #include <cstdio>
    #include <algorithm>
    using namespace std;
    #define low(i) ((i)&(-(i)))
     
    const int maxn=8e4+5;
     
    int n,m,tot,cnt,tim;
    int opt[maxn],x[maxn],y[maxn];
    int f[maxn][18],L[maxn],R[maxn];
    int tmp[maxn<<1],a[maxn],dep[maxn];
    int now[maxn],pre[maxn*2],son[maxn*2];
     
    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;
    }
     
    void add(int a,int b) {
        pre[++tot]=now[a];
        now[a]=tot,son[tot]=b;
    }
     
    void init() {
        cnt=n=read(),m=read();
        for(int i=1;i<=n;i++)tmp[i]=a[i]=read();
        for(int i=1;i<n;i++) {
            int a=read(),b=read();
            add(a,b),add(b,a);
        }
        for(int i=1;i<=m;i++) {
            opt[i]=read(),x[i]=read(),y[i]=read();
            if(!opt[i])tmp[++cnt]=y[i];
        }tot=cnt;sort(tmp+1,tmp+tot+1);
        cnt=unique(tmp+1,tmp+tot+1)-tmp-1;
        for(int i=1;i<=n;i++)
            a[i]=lower_bound(tmp+1,tmp+cnt+1,a[i])-tmp;
        for(int i=1;i<=m;i++)
            if(!opt[i])y[i]=lower_bound(tmp+1,tmp+cnt+1,y[i])-tmp;
    }
     
    int sum[maxn*180],ls[maxn*180],rs[maxn*180];
     
    struct segment_tree {
        int fake;
         
        void change(int p,int l,int r,int pos,int v) {
            while(1) {
                sum[p]+=v;if(l==r)break;
                int mid=(l+r)>>1;
                if(pos<=mid) {
                    if(!ls[p])ls[p]=++fake;
                    p=ls[p],r=mid;
                }
                else {
                    if(!rs[p])rs[p]=++fake;
                    p=rs[p],l=mid+1;
                }
            }
        }
    }T;
     
    struct TreeArray {
        int cnt1,cnt2,cnt3,cnt4;
        int rt[maxn<<1],u1[maxn],u2[maxn],u3[maxn],u4[maxn];
     
        void change(int pos,int v,int num) {
            for(int i=pos;i<=2*n;i+=low(i)) {
                if(!rt[i])rt[i]=++T.fake;
                T.change(rt[i],1,cnt,v,num);
            }
        }
     
        void query(int fa1,int fa2,int u,int v,int k) {
            int l=1,r=cnt,res=0;cnt1=cnt2=cnt3=cnt4=0;
            if(fa1)for(int i=L[fa1];i;i-=low(i))u1[++cnt1]=rt[i],res-=sum[rt[i]];
            for(int i=L[fa2];i;i-=low(i))u2[++cnt2]=rt[i],res-=sum[rt[i]];
            for(int i=L[u];i;i-=low(i))u3[++cnt3]=rt[i],res+=sum[rt[i]];
            for(int i=L[v];i;i-=low(i))u4[++cnt4]=rt[i],res+=sum[rt[i]];
            if(res<k) {puts("invalid request!");return;}
            while(l!=r) {
                res=0;int mid=(l+r)>>1;
                for(int i=1;i<=cnt1;i++)res-=sum[rs[u1[i]]];
                for(int i=1;i<=cnt2;i++)res-=sum[rs[u2[i]]];
                for(int i=1;i<=cnt3;i++)res+=sum[rs[u3[i]]];
                for(int i=1;i<=cnt4;i++)res+=sum[rs[u4[i]]];
                if(res>=k) {
                    l=mid+1;
                    for(int i=1;i<=cnt1;i++)u1[i]=rs[u1[i]];
                    for(int i=1;i<=cnt2;i++)u2[i]=rs[u2[i]];
                    for(int i=1;i<=cnt3;i++)u3[i]=rs[u3[i]];
                    for(int i=1;i<=cnt4;i++)u4[i]=rs[u4[i]];
                }
                else {
                    r=mid;k-=res;
                    for(int i=1;i<=cnt1;i++)u1[i]=ls[u1[i]];
                    for(int i=1;i<=cnt2;i++)u2[i]=ls[u2[i]];
                    for(int i=1;i<=cnt3;i++)u3[i]=ls[u3[i]];
                    for(int i=1;i<=cnt4;i++)u4[i]=ls[u4[i]];
                }
            }
            printf("%d
    ",tmp[l]);
        }   
    }bit;
     
    void dfs(int fa,int u) {
        L[u]=++tim,dep[u]=dep[fa]+1,f[u][0]=fa;
        bit.change(tim,a[u],1);
        for(int i=1;i<18;i++)
            f[u][i]=f[f[u][i-1]][i-1];
        for(int p=now[u],v=son[p];p;p=pre[p],v=son[p])
            if(v!=fa)dfs(u,v);
        R[u]=++tim;
        bit.change(tim,a[u],-1);
    }
     
    int lca(int u,int v) {
        if(dep[u]<dep[v])swap(u,v);
        for(int i=17;~i;i--)
            if(dep[f[u][i]]>=dep[v])
                u=f[u][i];
        if(u==v)return u;
        for(int i=17;~i;i--)
            if(f[u][i]!=f[v][i])
                u=f[u][i],v=f[v][i];
        return f[u][0];
    }
     
    void work() {
        for(int i=1;i<=m;i++) {
            int u=x[i],v=y[i];
            if(opt[i]==0) {
                bit.change(L[u],a[u],-1);
                bit.change(R[u],a[u],1);
                a[u]=v;
                bit.change(L[u],a[u],1);
                bit.change(R[u],a[u],-1);
            }
            else {
                int tmp1=lca(u,v),tmp2=f[tmp1][0];
                bit.query(tmp1,tmp2,u,v,opt[i]);
            }
        }
    }
     
    int main() {
        init();
        dfs(0,1);
        work();
        return 0;
    }
    
  • 相关阅读:
    Postfix 邮件服务器搭建
    DER、CRT、CER、PEM格式的证书及转换
    Apache SSL 服务搭建
    scapy 中的ARP
    关于linux特殊含义的转义符33
    关于javascript中defineProperty的学习
    python QT 编程之路
    python socket编程制作后门木马(原创)
    mybatis学习——映射器(mappers)
    mybatis学习——properties属性实现引用配置文件
  • 原文地址:https://www.cnblogs.com/AKMer/p/10176127.html
Copyright © 2011-2022 走看看