zoukankan      html  css  js  c++  java
  • [HNOI2016] 网络

    前言

    我不期望谁能看懂,写博客只是因为写这道题过程曲折,需要博客记录。

    人话:需要写博客平静自己的心情。

    题目

    洛谷

    LibreOJ

    讲解

    这道题思路不难。

    为了方便讲解,我们将题目中的交互信息叫做路径,其重要度叫做该路径的权值

    首先我们考虑如果有很多路径已经挂在了树上,我们怎么回答询问?

    考虑二分。

    直接二分答案,判断合法性的时候直接将可能的路径求交集,然后判断询问的点是否在该路径交集上即可。

    多个路径求交集可以将路径按权值排序后放到线段树上维护。

    由于此题需要求大量的 ( t LCA),所以我们需要高效的 ( t ST) 来求 (O(1)) 求。

    听着很简单是不是?等你写路径交集函数的时候就不会这么觉得了。

    当然这道题也可以用整体二分做。

    代码

    //12252024832524
    #include <cstdio>
    #include <cstring>
    #include <algorithm>
    #define TT template<typename T>
    using namespace std; 
    
    typedef long long LL;
    const int MAXN = 200005;
    int n,m;
    
    LL Read()
    {
        LL x = 0,f = 1;char c = getchar();
        while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
        while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
        return x * f;
    }
    TT void Put1(T x)
    {
        if(x > 9) Put1(x/10);
        putchar(x%10^48);
    }
    TT void Put(T x,char c = -1)
    {
        if(x < 0) putchar('-'),x = -x;
        Put1(x); if(c >= 0) putchar(c);
    }
    TT T Max(T x,T y){return x > y ? x : y;}
    TT T Min(T x,T y){return x < y ? x : y;}
    TT T Abs(T x){return x < 0 ? -x : x;}
    
    int head[MAXN],tot; 
    struct edge
    {
        int v,nxt;
    }e[MAXN << 1];
    void Add_Edge(int x,int y) 
    {
        e[++tot].v = y;
        e[tot].nxt = head[x];
        head[x] = tot;
    }
    void Add_Double_Edge(int x,int y) 
    {
        Add_Edge(x,y);
        Add_Edge(y,x);
    }
    int dfn[MAXN],dfntot,st[MAXN << 1][19],cnt,who[MAXN],lg[MAXN << 1],d[MAXN];
    int cs(int x,int y){return d[x] > d[y] ? y : x;}
    int cs2(int x,int y){return d[x] > d[y] ? x : y;}
    void dfs(int x,int fa)
    {
        d[x] = d[fa] + 1; 
        dfn[x] = ++dfntot;
        st[who[x] = ++cnt][0] = x;
        for(int i = head[x]; i ;i = e[i].nxt)
        {
            if(e[i].v == fa) continue;
            dfs(e[i].v,x);
            st[++cnt][0] = x;
        }
    }
    int opt[MAXN][4];
    int lca(int x,int y)
    {
        int u = who[x],v = who[y];
        if(u > v) swap(u,v);
        int ll = lg[v-u+1];
        return cs(st[u][ll],st[v-(1<<ll)+1][ll]);
    }
    
    int netot;
    struct Network
    {
        int x,val;
        Network(){}
        Network(int x1,int val1){
            x = x1;
            val = val1;
        }
        bool operator < (const Network &px)const{
            return val < px.val;
        }
    }net[MAXN];
    int to[MAXN];
    struct node
    {
        int u,v;
        node(){}
        node(int u1,int v1){
            u = u1;
            v = v1;
        }
        void fk(){if(dfn[u] > dfn[v]) swap(u,v);}
    }t[MAXN << 2];
    bool on(int x,node p)
    {
    	if(p.u < 0) return 0;
        int LCA = lca(p.u,p.v);
        if(lca(x,LCA) != LCA) return 0;
        p.fk();
    	int l1 = lca(p.u,x),l2 = lca(p.v,x);
    	if((l1 == LCA && l2 == x) || (l1 == x && l2 == LCA)) return 1;
    	return 0;
    }
    node merg(node p1,node p2)
    {
        if(!p1.u) return p2;
        if(!p2.u) return p1;
        if(p1.u < 0 || p2.u < 0) return node(-1,-1);
    	int LCA1 = lca(p1.u,p1.v),LCA2 = lca(p2.u,p2.v),cn1 = 0,cn2 = 0;
    	if(!on(LCA1,p2) && !on(LCA2,p1)) return node(-1,-1);
    	p1.fk(); p2.fk();
    	if(LCA1 == p1.u) cn1 = 1;
    	if(LCA2 == p2.u) cn2 = 1;
    	if(cn2) swap(p1,p2),swap(LCA1,LCA2),swap(cn1,cn2);
    	if(cn1 && !cn2)
    	{
    		if(cn2)//chain & chain
    			return node(dfn[p1.u] > dfn[p2.u] ? p1.u : p2.u,dfn[p1.v] < dfn[p2.v] ? p1.v : p2.v);
    		else//chain & turning
    		{
    			int V = cs2(cs2(lca(p1.u,p2.u),lca(p1.u,p2.v)),cs2(lca(p1.v,p2.u),lca(p1.v,p2.v)));
    			return node(on(LCA2,p1) ? LCA2 : p1.u,V);
    		}
    	}
    	else//turning & turning
    	{
    		if(LCA1 == LCA2) 
    		{
    			node ret1 = node(lca(p1.u,p2.u),lca(p1.v,p2.v));
    			node ret2 = node(lca(p1.u,p2.v),lca(p1.v,p2.u));
    			if(ret1.u == ret1.v) return ret2;
    			return ret1;
    		}
    		int U,V;
    		if(on(LCA1,p2)) U = LCA1;
    		else U = LCA2;
    		V = cs2(cs2(lca(p1.u,p2.u),lca(p1.u,p2.v)),cs2(lca(p1.v,p2.u),lca(p1.v,p2.v)));
    		return node(U,V); 
    	}
    }
    #define lc (x<<1) 
    #define rc (x<<1|1) 
    struct SegmentTree
    {
    	int ex[MAXN << 2];
    	
        void up(int x){t[x] = merg(t[lc],t[rc]);ex[x] = ex[lc] + ex[rc];}
    
        void Add(int x,int l,int r,int pos,node ad)
        {
            if(l == r) {t[x] = ad;ex[x] = 1;return;}
            int mid = (l+r) >> 1;
            if(pos <= mid) Add(lc,l,mid,pos,ad);
            else Add(rc,mid+1,r,pos,ad);
            up(x);
        }
    
        void Del(int x,int l,int r,int pos)
        {
            if(l == r) {t[x] = node(0,0);ex[x] = 0;return;}
            int mid = (l+r) >> 1;
            if(pos <= mid) Del(lc,l,mid,pos);
            else Del(rc,mid+1,r,pos);
            up(x);
        }
    
        int Query(int x,int l,int r,int pos,node now)
        {
            if(l == r) return net[l].val;
            node n1 = merg(now,t[rc]);
            int mid = (l+r) >> 1;
            if(!on(pos,n1) && ex[rc]) return Query(rc,mid+1,r,pos,now);
            return Query(lc,l,mid,pos,n1);
        }
    }ST;
    
    int main()
    {
    //  freopen(".in","r",stdin);
    //  freopen(".out","w",stdout);
        n = Read(); m = Read();
        for(int i = 1;i < n;++ i) Add_Double_Edge(Read(),Read());
        dfs(1,0);
        lg[0] = -1;
        for(int i = 1;i <= cnt;++ i) lg[i] = lg[i>>1] + 1;
        for(int i = 1;i <= lg[cnt];++ i)
            for(int j = 1;j+(1<<i)-1 <= cnt;++ j)
                st[j][i] = cs(st[j][i-1],st[j+(1<<(i-1))][i-1]);
        for(int i = 1;i <= m;++ i)
        {
            opt[i][0] = Read();
            if(!opt[i][0]) 
            {
                for(int j = 1;j <= 3;++ j) opt[i][j] = Read();
                net[++netot] = Network(i,opt[i][3]);
            }
            else opt[i][1] = Read();
        }
        sort(net+1,net+netot+1);
        for(int i = 1;i <= netot;++ i) to[net[i].x] = i;
        for(int i = 1;i <= m;++ i)
        {
            if(!opt[i][0]) ST.Add(1,1,netot,to[i],node(opt[i][1],opt[i][2]));
            else if(opt[i][0] == 1) ST.Del(1,1,netot,to[opt[i][1]]);
            else 
            {
                if(!ST.ex[1] || on(opt[i][1],t[1])) Put(-1,'
    ');
                else Put(ST.Query(1,1,netot,opt[i][1],node(0,0)),'
    ');
            }
        }
        return 0;
    }
    

    在画了一万张路径相交的图之后,终于写出了这份代码。

    此代码已经经过精简(指删掉调试信息),但仍然有215行。

    似乎删掉调试信息之前有260行+。

  • 相关阅读:
    关于字节对齐以及内存占用
    关于HandlerThread的分析
    关于栈和队列的相关操作
    自定义控件(View的绘制流程源码解析)
    关于采用github.io搭建个人博客
    算法题解
    关于Android中ArrayMap/SparseArray比HashMap性能好的深入研究
    ADB server didn't ACK * failed to start daemon *
    Handler 、 Looper 、Message
    KMP字符串模式匹配详解(转)
  • 原文地址:https://www.cnblogs.com/PPLPPL/p/15017766.html
Copyright © 2011-2022 走看看