zoukankan      html  css  js  c++  java
  • [ZJOI2019]语言

    [ZJOI2019]语言 

    法一: O(nlog^3)树剖+矩形面积并

    法二:O(nlog^2)

    一个点能到达的点是所有经过它的链的链并的大小

    给出m个链求链并:

    类似虚树

    dfn序排序,ans+=dep[mem[i]]-dep[lca(mem[i],mem[i-1])]

    每个边一定会统计到。

    维护?

    每个链树剖拆成logn份,线段树分治+线段树

    下标都是dfn序

    dfn相邻的贡献答案

    法三:O(nlogn)

    不再从dfn序列孤立地考虑树链

    从树上直接考虑

    经过一个点x的链一定一端在x的子树,启发我们线段树合并!

    下标还是dfn序

    树上差分打标记,8个标记。

    lca可以O(1)求

    #include<bits/stdc++.h>
    #define reg register int
    #define il inline
    #define fi first
    #define se second
    #define mk(a,b) make_pair(a,b)
    #define numb (ch^'0')
    #define pb push_back
    #define solid const auto &
    #define enter cout<<endl
    #define pii pair<int,int>
    using namespace std;
    typedef long long ll;
    template<class T>il void rd(T &x){
        char ch;x=0;bool fl=false;
        while(!isdigit(ch=getchar()))(ch=='-')&&(fl=true);
        for(x=numb;isdigit(ch=getchar());x=x*10+numb);
        (fl==true)&&(x=-x);
    }
    template<class T>il void output(T x){if(x/10)output(x/10);putchar(x%10+'0');}
    template<class T>il void ot(T x){if(x<0) putchar('-'),x=-x;output(x);putchar(' ');}
    template<class T>il void prt(T a[],int st,int nd){for(reg i=st;i<=nd;++i) ot(a[i]);putchar('
    ');}
    
    namespace Miracle{
    const int N=1e5+5;
    int n,m;
    struct node{
        int nxt,to;
    }e[2*N];
    int hd[N],cnt;
    void add(int x,int y){
        e[++cnt].nxt=hd[x];
        e[cnt].to=y;
        hd[x]=cnt;
    }
    
    int dfn[N],df,fdfn[N];
    int st[N],num;
    int dep[N];
    int mem[2*N];
    int fa[N];
    void dfs(int x,int d){
        dep[x]=d;dfn[x]=++df;
        fdfn[df]=x;
        st[x]=++num;mem[num]=x;
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa[x]) continue;
            fa[y]=x;
            dfs(y,d+1);
            mem[++num]=x;
        }
    }
    int anc[2*N][20];
    int lg[2*N];
    int lca(int x,int y){
        if(!x||!y) return 0;
        if(st[x]>st[y]) swap(x,y);
        x=st[x],y=st[y];
        int len=lg[y-x+1];
        int p1=anc[x][len],p2=anc[y-(1<<len)+1][len];
        return dep[p1]<dep[p2]?p1:p2;
    }
    int con(int x,int y){
        if(!x||!y) return 0;
        return dep[fdfn[y]]-dep[lca(fdfn[x],fdfn[y])];
    }
    struct tr{
        int ls,rs;
        int le,ri;
        int tag;
        int ans;
    }t[N*160];
    #define mid ((l+r)>>1)
    int tot;
    void pushup(int x){
        t[x].ans=t[t[x].ls].ans+t[t[x].rs].ans+con(t[t[x].ls].ri,t[t[x].rs].le);
        t[x].ri=t[t[x].rs].ri?t[t[x].rs].ri:t[t[x].ls].ri;
        t[x].le=t[t[x].ls].le?t[t[x].ls].le:t[t[x].rs].le;
    }
    int rt[N];
    void upda(int &x,int l,int r,int p,int c){
        if(!x) x=++tot;
        if(l==r){
            t[x].tag+=c;
            if(t[x].tag>0) t[x].le=t[x].ri=l;
            else t[x].le=t[x].ri=0;
            return;
        }
        if(p<=mid) upda(t[x].ls,l,mid,p,c);
        else upda(t[x].rs,mid+1,r,p,c);
        pushup(x);
    }
    int merge(int x,int y,int l,int r){
        if(!x||!y) return x+y;
        if(l==r){
            t[x].tag+=t[y].tag;
            if(t[x].tag>0) t[x].le=t[x].ri=l;
            else t[x].le=t[x].ri=0;
            return x;
        }
        t[x].ls=merge(t[x].ls,t[y].ls,l,mid);
        t[x].rs=merge(t[x].rs,t[y].rs,mid+1,r);
        pushup(x);
        return x;
    }
    ll ans;
    void sol(int x){
        for(reg i=hd[x];i;i=e[i].nxt){
            int y=e[i].to;
            if(y==fa[x]) continue;
            sol(y);
            rt[x]=merge(rt[x],rt[y],1,n);
        }
        int now=t[rt[x]].ans+dep[fdfn[t[rt[x]].le]]-dep[fa[lca(fdfn[t[rt[x]].le],fdfn[t[rt[x]].ri])]];
        // cout<<" sol "<<x<<" now "<<now<<" ans "<<t[rt[x]].ans<<" "<<endl;
        if(now) ans+=now-1;
    }
    int main(){
        rd(n);rd(m);
        int x,y;
        for(reg i=1;i<n;++i){
            rd(x);rd(y);
            add(x,y);add(y,x);
        }
        dfs(1,1);
        for(reg i=1;i<=num;++i) {
            anc[i][0]=mem[i];
            lg[i]=(i>>(lg[i-1]+1)?lg[i-1]+1:lg[i-1]);
        }
        for(reg j=1;j<=17;++j){
            for(reg i=1;i+(1<<j)-1<=num;++i){
                anc[i][j]=dep[anc[i][j-1]]<dep[anc[i+(1<<(j-1))][j-1]]?anc[i][j-1]:anc[i+(1<<(j-1))][j-1];
            }
        } 
        for(reg i=1;i<=m;++i){
            rd(x);rd(y);
            int z=lca(x,y);
            // cout<<" zz "<<z<<endl;
            upda(rt[x],1,n,dfn[x],1);
            upda(rt[x],1,n,dfn[y],1);
            upda(rt[y],1,n,dfn[x],1);
            upda(rt[y],1,n,dfn[y],1);
            upda(rt[z],1,n,dfn[x],-1);
            upda(rt[z],1,n,dfn[y],-1);
            if(fa[z]){
                upda(rt[fa[z]],1,n,dfn[x],-1);
                upda(rt[fa[z]],1,n,dfn[y],-1);
            }
        }
        sol(1);
        // cout<<" 00 "<<rt[0]<<" "<<t[0].ans<<" "<<t[0].ls<<" "<<t[0].rs<<" "<<t[0].le<<" "<<t[0].ri<<" "<<t[0].tag<<endl;
        ans/=2;
        ot(ans);
        return 0;
    }
    
    }
    signed main(){
        Miracle::main();
        return 0;
    }
    
    /*
       Author: *Miracle*
    */
  • 相关阅读:
    0034 CSS精灵技术:sprite(重点)
    0033 溢出的文字省略号显示:white-space、overflow、text-overflow
    0032 垂直对齐:vertical-align(图片、表单和文字对齐,去除图片底侧空白缝隙)
    0031 CSS用户界面样式:鼠标样式cursor、轮廓线 outline、防止拖拽文本域resize
    0030 元素的显示与隐藏:dispaly、visibility、overflow
    0029 css定位:相对、绝对、固定、绝对定位盒子居中、z-index、绝对定位改变display属性、案例
    0027 chrome调试工具
    0026 页面布局流程
    0025 CSS属性书写顺序
    0024 Photoshop 切图
  • 原文地址:https://www.cnblogs.com/Miracevin/p/10805577.html
Copyright © 2011-2022 走看看