zoukankan      html  css  js  c++  java
  • 红蓝图 kruskal重构树+dfs序+线段树合并

    红蓝图 kruskal重构树+dfs序+线段树合并

    题解:

    如果不会kruskal重构树,建议先写 D. Graph and Queries 并查集+线段树+kruskal重构树

    • 首先对查询按照 t 从大到小排序,然后按照权值从大到小建一棵kruskal重构树,然后dfs求出每一个节点的dfs序,顺便求出每一个询问节点的子树节点。
    • 对于每一个节点都建一棵动态开点的线段树,然后对查询按照 t 从小到大排序,边建线段树边输出询问。
    #include <bits/stdc++.h>
    using namespace std;
    inline char nc(){
        static char buf[100000],*p1=buf,*p2=buf;
        return p1==p2&&(p2=(p1=buf)+fread(buf,1,100000,stdin),p1==p2)?EOF:*p1++;
    }
    inline int read()
    {
        register int x=0,f=1;register char ch=getchar();
        while(ch<'0'||ch>'9'){if(ch=='-')f=-1;ch=getchar();}
        while(ch>='0'&&ch<='9')x=(x<<3)+(x<<1)+ch-'0',ch=getchar();
        return x*f;
    }
    inline void write(register int x)
    {
        if(!x)putchar('0');if(x<0)x=-x,putchar('-');
        static int sta[20];register int tot=0;
        while(x)sta[tot++]=x%10,x/=10;
        while(tot)putchar(sta[--tot]+48);
    }
    const int maxn = 1e6+10;
    int a[maxn],b[maxn],c[maxn];
    struct node{
        int x,t,id;
        node(int x=0,int t=0,int id=0):x(x),t(t),id(id){}
    }e[maxn];
    bool cmp(node a,node b){
        return a.t<b.t;
    }
    int head[maxn],to[maxn<<1],nxt[maxn<<1],cnt;
    void add(int u,int v){
        // printf("u = %d v = %d
    ", u,v);
        ++cnt,to[cnt]=v,nxt[cnt]=head[u],head[u]=cnt;
        ++cnt,to[cnt]=u,nxt[cnt]=head[v],head[v]=cnt;
    }
    int f[maxn],now;
    int find(int x){
        return f[x]==x?x:f[x]=find(f[x]);
    }
    
    void unite(int x,int y){
        x = find(x),y = find(y);
        if(x == y) return ;
        ++now,add(x,now),add(y,now);
        f[now] = f[x] = f[y] = now;
    }
    int subTree[maxn],el[maxn],er[maxn],tot;
    void dfs(int u,int pre){
        el[u] = ++tot;
        for(int i=head[u];i;i=nxt[i]){
            int v = to[i];
            if(v == pre) continue;
            dfs(v,u);
        }
        er[u] = tot;
    }
    int root[maxn],sum[maxn<<2],sz,lc[maxn<<2],rc[maxn<<2];
    void push_up(int id){
        sum[id] = sum[lc[id]] + sum[rc[id]];
    }
    void update(int &id,int l,int r,int pos){
        if(!id) id = ++sz;
        if(l==r){
            sum[id] = 1;
            return ;
        }
        int mid = (l+r)>>1;
        if(pos<=mid) update(lc[id],l,mid,pos);
        if(pos>mid) update(rc[id],mid+1,r,pos);
        push_up(id);
    }
    int merge(int x,int y,int l,int r){
        if(!x) return y;
        if(!y) return x;
        if(l==r){
            sum[x] += sum[y];
            return x;
        }
        int mid = (l+r)>>1;
        lc[x] = merge(lc[x],lc[y],l,mid);
        rc[x] = merge(rc[x],rc[y],mid+1,r);
        push_up(x);
        return x;
    }
    int ans[maxn];
    int query(int id,int l,int r,int x,int y){
        // printf("query:id = %d l = %d r = %d x =%d y = %d
    ", id,l,r,x,y);
        if(!id) return 0;
        if(x<=l&&y>=r) return sum[id];
        int mid = (l+r)>>1,ans = 0;
        if(x<=mid) ans += query(lc[id],l,mid,x,y);
        if(y>mid) ans += query(rc[id],mid+1,r,x,y);
        return ans;
    }
    
    void debug(int id,int l,int r){
        if(!id) return ;
        printf("id = %d l = %d r = %d sum=%d
    ", id,l,r,sum[id]);
        if(l==r) return;
        int mid = (l+r)>>1;
        debug(lc[id],l,mid);
        debug(rc[id],mid+1,r);
    }
    
    int main(){
        int n = read(),m = read(),q = read();
        now = n,cnt = 0,tot = 0,sz = 0;
        for(int i=1;i<=n+m;i++) f[i] = i;
        for(int i=1;i<=m;i++){
            a[i] = read() + 1,b[i] = read() + 1,c[i] = read();
        }
        for(int i=1;i<=q;i++){
            int x = read() + 1,t = read();
            e[i] = node(x,t,i);
        }
        int cur = m;
        sort(e+1,e+1+q,cmp);
        for(int i=q;i>=1;i--){
            while(cur>=1&&cur>=e[i].t){
                if(c[cur]) unite(a[cur],b[cur]);
                cur--;
            }
            subTree[i] = find(e[i].x);
        }
        for(int i=1;i<=n+m;i++){
            find(i);
            if(f[i]==i) dfs(i,0);
        }
        for(int i=1;i<=n;i++) update(root[i],1,now,el[i]);
        cur = 1;
        for(int i=1;i<=n;i++) f[i] = i;
        for(int i=1;i<=q;i++){
            while(cur<=m&&cur<=e[i].t){
                if(!c[cur]) {
                    int x = find(a[cur]),y = find(b[cur]);
                    if(x!=y){ 
                        root[x]=root[y]=merge(root[x],root[y],1,now);
                        f[x] = y;
                    }
                }
                cur++;
            }
            int pos = root[find(e[i].x)];
            ans[e[i].id] = query(pos,1,now,el[subTree[i]],er[subTree[i]]);
        }
        for(register int i=1;i<=q;++i) write(ans[i]),puts("");
        return 0;
    }
    
    
    
  • 相关阅读:
    Unity3d vector3.forward和transform.forward的区别!
    UGUI实现摇杆
    UGUI实现拼图游戏
    Unity3d打包发布Android程序
    兼容PC和手机触摸代码
    unity3d中Transform组件变量详解
    运算符重载
    扩展方法
    string.Format格式化输出
    网络编程之Socket的TCP协议实现客户端与客户端之间的通信
  • 原文地址:https://www.cnblogs.com/EchoZQN/p/13818496.html
Copyright © 2011-2022 走看看