zoukankan      html  css  js  c++  java
  • P2416 【泡芙】

    一个非前缀和做法。

    思路:首先,将图通过 (tarjan) 的无向图连通分量缩成一个无向无环图,即一棵树。那么,剩下的我们就是要判断一条路径上是否存在权值为 (1) 的边点了。这里所谓的边和点都是指新图上的。那么,对于内部包含原图权值为 (1) 的边的边双连通,我们记一个数组 (val),代表其内部包含 (1)

    但是,注意,在连通与连通之间,可能仍然存在权值为 (1) 的边。所以,我们考虑边权下放点权,记录到一个 (sum) 数组中。

    重点!

    在查询的时候,(lca) 所代表的边不能被查询,但是其点权应该被查询,所以应该分开讨论。

    上代码:

    #include <bits/stdc++.h>
    using namespace std;
    #define N 1000010
    
    template <class T>
    inline void read(T& a){
        T x = 0, s = 1;
        char c = getchar();
        while(!isdigit(c)){
            if(c == '-') s = -1;
            c = getchar();
        }
        while(isdigit(c)){
            x = x * 10 + (c ^ '0');
            c = getchar(); 
        }
        a = x * s; 
        return ; 
    }
    
    struct tu{
    
        struct node{
         int u, v, w, next;
        } t[N << 1];
        int f[N]; 
    
        int bian;
        inline void add(int u, int v, int w){
            t[++bian] = (node){u, v, w, f[u]}, f[u] = bian;
            return ; 
        }
    
    } T, G; 
    
    int n, m; 
    int val[N]; 
    
    namespace suodian{      // 无向图的缩点 
    	
    	int dfn[N], low[N], id = 0;
    	int stac[N], top = 0; 
    	int scc[N], cnt = 0;
    
    	void tarjan(int now, int fa){
      		dfn[now] = low[now] = ++id; 
      		stac[++top] = now; 
       	    for(int i = G.f[now]; i; i = G.t[i].next){
                int v = G.t[i].v;
        		if(!dfn[v]){
        	        tarjan(v, now); 
        	        low[now] = min(low[now], low[v]); 
        	    }
        	    else if(v != fa) low[now] = min(low[now], dfn[v]); 
        	}
        	if(low[now] == dfn[now]){
            	int cur;
            	cnt++;
            	do{
                	cur = stac[top--];
           		    scc[cur] = cnt; 
            	}while(cur != now); 
        	}
       		 return ; 
    	}
    
    	void work(){
    		for(int i = 1; i <= n; i++)
    			if(!dfn[i]) tarjan(i, 0);  // 虽然题目中说了保证连通,但还是保险一点 
    		for(int i = 1; i <= G.bian; i++){
      		    int u = G.t[i].u, v = G.t[i].v; 
      	        if(scc[u] == scc[v]){
      	          val[scc[u]] |= G.t[i].w;   // 判断是否有 1
      	      	}
        	    else if(scc[u] != scc[v])
        	        T.add(scc[u], scc[v], G.t[i].w); 
        	}
        	return ; 
    	} 
    
    } 
    
    int fa[N], son[N], siz[N], top[N], deth[N];
    int sum[N]; 
    int dfn[N], rev[N], id = 0; 
    
    void dfs1(int now, int father){
        sum[now] |= val[now];    // 全部累积到 sum 上
        fa[now] = father;
        siz[now] = 1;
        deth[now] = deth[father] + 1;
        for(int i = T.f[now]; i; i = T.t[i].next){
            int v = T.t[i].v;
            if(v != father){
                dfs1(v, now);
                sum[v] |= T.t[i].w;      // 新权值累积下去
                siz[now] += siz[v]; 
                if(siz[v] > siz[son[now]])
                    son[now] = v; 
            }
        }
        return ; 
    }
    
    void dfs2(int now, int tp){
        top[now] = tp;
        dfn[now] = ++id, rev[id] = now; 
        if(!son[now]) return ;
        dfs2(son[now], tp);
        for(int i = T.f[now]; i; i = T.t[i].next){
            int v = T.t[i].v;
            if(v != fa[now] && v != son[now])
                dfs2(v, v); 
        }
        return ; 
    }
    
    struct Segment_tree{   // 路径求和 
        struct node{
            int w; 
        } e[N << 2];
    
        #define lson (o<<1)
        #define rson (o<<1|1)
    
        inline void pushup(int o){
            e[o].w = e[lson].w + e[rson].w;
            return ; 
        }
    
        void build(int o, int l, int r){
            if(l == r){
                e[o].w = sum[rev[l]];
                return ; 
            }
            int mid = l + r >> 1;
            build(lson, l, mid);
            build(rson, mid + 1, r);
            pushup(o);
            return ; 
        }
    
        int query(int o, int l, int r, int in, int end){
            if(l > end || r < in) return 0;
            if(l >= in && r <= end) return e[o].w;
            int mid = l + r >> 1;
            return query(lson, l, mid, in, end) + query(rson, mid + 1, r, in, end); 
        }
    
    } tree; 
    
    int ask_he(int x, int y){  // 经典树剖对路径操作 
        int ans = 0;
        while(top[x] != top[y]){
            if(deth[top[x]] < deth[top[y]]) swap(x, y); 
            ans += tree.query(1, 1, n, dfn[top[x]], dfn[x]); 
            x = fa[top[x]]; 
        }
        if(deth[x] > deth[y]) swap(x, y); 
        ans += tree.query(1, 1, n, dfn[x] + 1, dfn[y]);
        if(val[x]) ans++; 
        return ans; 
    }
    
    int main(){
    //	freopen("hh.txt", "r", stdin); 
        read(n), read(m);
        for(int i = 1; i <= m; i++){
            int x, y, w;
            read(x), read(y), read(w);
            G.add(x, y, w); G.add(y, x, w); 
        }
        suodian::work();    // 缩点 
        dfs1(1, 0);
        dfs2(1, 0);    // 树剖 
        tree.build(1, 1, n); 
        int q; read(q);
        while(q--){
            int s, ht;
            read(s), read(ht); 
            s = suodian::scc[s], ht = suodian::scc[ht];     // 注意转换成新图 
            ask_he(s, ht) >= 1 ? puts("YES") : puts("NO"); 
        }
        return 0; 
    }
    
  • 相关阅读:
    BZOJ 4260 Codechef REBXOR
    [SHOI2008]小约翰的游戏John
    [POI2016]Nim z utrudnieniem
    [CQOI2013]棋盘游戏
    [SDOI2016]硬币游戏
    [BZOJ3083]遥远的国度
    [Luogu3727]曼哈顿计划E
    [HihoCoder1413]Rikka with String
    [CF666E]Forensic Examination
    [BZOJ4004][JLOI2015]装备购买
  • 原文地址:https://www.cnblogs.com/wondering-world/p/14083890.html
Copyright © 2011-2022 走看看